Skip to content

cmath.log(0, base) returns (-inf+nanj) instead of raising ValueError #161972

Description

@Broyojo

Bug report

cmath.log(0) raises ValueError, but cmath.log(0, base) returns a value such as (-inf+nanj) for most bases. In cmath_log_impl, the domain error from c_log(z) is stored in errno, and the second call c_log(base) resets errno to 0 before it is checked.

import cmath, math

cmath.log(0)       # ValueError: math domain error
cmath.log(0, 2)    # (-inf+nanj)
cmath.log(0, -1)   # (nan+infj)
math.log(0, 2)     # ValueError: expected a positive input

Expected: cmath.log(0, base) raises ValueError: math domain error, the same as cmath.log(0) and math.log(0, 2). A zero or one base already raises (cmath.log(2, 0), cmath.log(2, 1)), because there the error comes from the second call or from the division.

CPython versions tested on:

3.15, CPython main branch

Operating systems tested on:

Linux


Found while building a Lean 4 model of CPython (https://broyojo.com/python-formalization/). AI tools (Claude) helped investigate the findings and prepare this report. The examples were rerun on CPython 3.15.2 and main, and the report received technical review. Record: mathint-cmath-log-base-errno

Linked PRs

Activity

  1. ZeroIntensity commented on Nov 14, 2026

    @ZeroIntensity
    Member

    cc @skirpichev

    I suspect that changing this will probably break code.

  2. skirpichev commented on Nov 14, 2026

    @skirpichev
    Member

    This is because of incorrect working with errno in the c_log() helper:

    errno = 0;

    Rather we should keep errno unmodified or save/restore it on success.

    I suspect that changing this will probably break code.

    Maybe, but I think it worth. We should keep in mind general rule for the cmath module, given in the comment (that might be exposed as an implementation detail like in the math module):

    /* First, the C functions that do the real work. Each of the c_*
    functions computes and returns the C99 Annex G recommended result
    and also sets errno as follows: errno = 0 if no floating-point
    exception is associated with the result; errno = EDOM if C99 Annex
    G recommends raising divide-by-zero or invalid for this result; and
    errno = ERANGE where the overflow floating-point signal should be
    raised.

    The C standard (hopefully) has no two-argument log() function, but it's nothing more than a quotient of two logarithms. If either argument is 0 - we have log(0) in one operands of the division, that raises the "divide-by-zero" exception. And it should be enabled for the whole quotient as well.

    In fact, sometimes such return values might be helpful, see #133895. But that's a separate feature request.

    We should only decide whether the current behavior must be deprecated first. IMO, it's better just fix things. It's a bug.

    CC @mdickinson

  3. tanveer-arch commented on Nov 14, 2026

    @tanveer-arch

    I'd like to take this on. cmath.log(0) raises ValueError, but cmath.log(0, base) returns (-inf+nanj) because the second c_log(base) call resets errno before it's checked. I'm working on a fix in cmath_log_impl plus a regression test.

  4. Broyojo commented on Nov 14, 2026

    @Broyojo
    ContributorAuthor

    @tanveer-arch please go ahead, I won't open a PR for this one. Following @skirpichev's suggestion to fix it in c_log() makes sense. In case it helps with the test: besides cmath.log(0, 2), I'd check bases -1 and 1j (which currently give (nan+infj)), 0j/-0.0/complex(-0.0, -0.0) as the argument, inf and nan bases, and that cmath.log(2, 0), cmath.log(2, 1) and a non-numeric base keep their current errors.

  5. added a commit that references this issue on Nov 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions