Skip to content

ValueError for math.atan2(0.0, 0.0) and cmath.phase(0.0) using icx #153144

Open

Description

@hpkfft

Bug report

Bug description:

The math function atan2 and the cmath function phase should not raise ValueError when their arguments are zero. This is true when building CPython using an officially supported compiler such as GCC:

>>> import math
>>> import cmath
>>> math.atan2(0.0, 0.0)
0.0
>>> cmath.phase(complex(0.0, 0.0))
0.0
>>> math.atan2(0.0, -0.0)
3.141592653589793
>>> cmath.phase(complex(-0.0, 0.0))
3.141592653589793

However, The C23 standard (ISO/IEC 9899:2024) in section 7.12.4.4 for atan2 states:

A domain error may occur if both arguments are zero.

The Intel math library version 2026.0.0 sets errno to EDOM for these cases. See also PR #152825. Thus:

>>> import math
>>> import cmath
>>> math.atan2(0.0, 0.0)
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    math.atan2(0.0, 0.0)
    ~~~~~~~~~~^^^^^^^^^^
ValueError: math domain error
>>> cmath.phase(complex(0.0, 0.0))
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    cmath.phase(complex(0.0, 0.0))
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
ValueError: math domain error
>>> math.atan2(0.0, -0.0)
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    math.atan2(0.0, -0.0)
    ~~~~~~~~~~^^^^^^^^^^^
ValueError: math domain error
>>> cmath.phase(complex(-0.0, 0.0))
Traceback (most recent call last):
  File "<python-input-5>", line 1, in <module>
    cmath.phase(complex(-0.0, 0.0))
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
ValueError: math domain error

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Jul 5, 2026
  2. skirpichev commented on Jul 6, 2026

    @skirpichev
    Member

    The math function atan2 and the cmath function phase should not raise ValueError when their arguments are zero.

    Why?

    The C standard has no phase function, though it's just carg(), and here we have:

    Errors and special cases are handled as if the function is implemented as atan2(cimag(z), creal(z))

    In turn, you noted, that C standard says (long time ago in fact) for atan2:

    A domain error may occur if both arguments are zero.

    Also, in section 7.12.1:

    On a domain error, the function returns an implementation-defined value; if the integer expression math_errhandling & MATH_ERRNO is nonzero, the integer expression errno acquires the value EDOM; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the "invalid" floating-point excep-
    tion is raised.

    That's interesting, because Annex F.10.1.4 also says:

    atan2(0, 0) does not raise the "invalid" floating-point exception, nor does atan2(y, 0) raise the "divide-by-zero" floating-point exception.

    So, assuming the icc supports Annex F nowadays - the described behavior looks as a compiler bug. Though, I don't think that icc defines some __STDC_IEC_60559_* macro. If so, I don't think we can count this as a platform bug and introduce some workaround (like ignoring errno).

    The math/cmath modules should be thin wrappers over system libm. And in this case it's so: EDOM from the libm's function is correctly translated to the ValueError exception.

  3. added
    pendingThe issue will be closed if no feedback is provided
    on Jul 6, 2026
  4. hpkfft commented on Jul 6, 2026

    @hpkfft
    ContributorAuthor

    The math/cmath modules should be thin wrappers over system libm.

    Is that true? Or, does Python instead strive to present consistent math functions regardless of the system?

    In general, on an IEEE-754 platform the aim is to follow the C99
    standard, including Annex 'F', whenever possible. Where the
    standard recommends raising the 'divide-by-zero' or 'invalid'
    floating-point exceptions, Python should raise a ValueError. Where
    the standard recommends raising 'overflow', Python should raise an
    OverflowError. In all other circumstances a value should be
    returned.

    Using icx and the Intel math library, atan2(0, 0) returns the correct value. It also sets errno to EDOM. This appears to be allowed by the C standard. C programmers can look at errno or not, as they choose. What should Python do--would users prefer to get the result (the same result calculated by glibc) or get ValueError? That seems to be a choice that's up to Python to make.

    What is the motivation for examining errno for atan2()? Is there a situation (on any platform with any compiler) in which Python does not want to return the floating-point result? [This is a genuine question. I don't know whether there's some platform with a math library that does something for atan2() that I have not considered.] On the other hand, if CPython is reading errno for atan2() and then ignoring it here and here, then it seems better not to read it in the first place (which is what this PR does).

    If, philosophically, the math/cmath modules should be thin wrappers over system libm, then would you support changing the tests in Lib/test/test_math.py and Lib/test/test_cmath.py to allow ValueError as a correct result for atan2(0,0) and phase(0), respectively?

  5. hpkfft commented on Jul 6, 2026

    @hpkfft
    ContributorAuthor

    Regarding the floating-point return value, Annex F specifies

    atan2(+0, -0) returns Pi
    atan2(-0, -0) returns -Pi
    atan2(+0, +0) returns +0
    atan2(-0, +0) returns -0

    So, at least, the correct return value is unambiguous is Python prefers to always return a value regardless of whether the system/platform math library sets errno.

  6. skirpichev commented on Jul 6, 2026

    @skirpichev
    Member

    Is that true? Or, does Python instead strive to present consistent math functions regardless of the system?

    Yes. You might try to convince people change this on the d.p.o (ideas). Good luck.

    Using icx and the Intel math library, atan2(0, 0) returns the correct value. It also sets errno to EDOM.

    What about floating-point exceptions?

    What is the motivation for examining errno for atan2()?

    We do this just as for other libm's functions. See e.g. math_1() wrapper. The atan2() just is not a special one.

    Regarding the floating-point return value, Annex F specifies

    Unfortunately, I suspect that the intel compiler doesn't announce support for that Annex.

    If that was the case - it would be a platform bug, because:

    1. "atan2(0, 0) does not raise the "invalid" floating-point exception"
      but
    2. "On a domain error, the function returns an implementation-defined value; if the integer expression math_errhandling & MATH_ERRNO is nonzero, the integer expression errno acquires the value EDOM; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the "invalid" floating-point exception is raised."

    See #138573 for a similar issue.

  7. hpkfft commented on Jul 6, 2026

    @hpkfft
    ContributorAuthor

    Using icx and the Intel math library, atan2(0, 0) returns the correct value. It also sets errno to EDOM.

    What about floating-point exceptions?

    The only floating-point exception (if it were unmasked) is INEXACT for when the infinitely precise result is Pi.
    See compiler explorer

    We do this just as for other libm's functions.

    So, no reason? Just easier to re-use existing code?

    The C standard allows setting errno to EDOM when both arguments are zero. Intel's math library does this.
    The C standard does not allow atan2 to cause invalid nor divide-by-zero. Intel's math library does neither.
    The C standard in Annex F prescribes return values when both arguments are zero. Intel's math library follows this.

    You seem to be arguing that statements (1) and (2) imply that a math library CANNOT (according to the standard) set errno to EDOM. But the standard clearly says it's OK to do so.
    I think (2) simply provides a general mechanism for converting a domain error to an invalid floating-point exception.
    Probably, (1) should say "atan2(0, 0) does not itself raise the 'invalid' floating-point exception but general mechanisms for converting domain errors to the 'invalid' floating-point exception still apply"

    I think it would be a mistake for Python's math.atan2 and cmath.phase to allow the compiler's math library's setting of errno to determine whether or not to raise ValueError when the functions' arguments are zero. Python's users would be better served by following the statement written in mathmodule.c, "Where the standard recommends raising the 'divide-by-zero' or 'invalid' floating-point exceptions, Python should raise a ValueError. Where the standard recommends raising 'overflow', Python should raise an OverflowError. In all other circumstances a value should be returned."

  8. skirpichev commented on Jul 7, 2026

    @skirpichev
    Member

    The only floating-point exception (if it were unmasked) is INEXACT for when the infinitely precise result is Pi. See compiler explorer

    Hmm, indeed. I did additional tests and now it looks as a bug for me: https://godbolt.org/z/Teqvfvaq5

    icx declares conformance to the Annex F, which says that no "invalid" exceptions should be reported. On another hand, it sets EDOM. But then it must raise an "invalid" exception if math_errhandling & MATH_ERREXCEPT is nonzero.

    So, no reason?

    Why we should handle errors differently?

    You seem to be arguing that statements (1) and (2) imply that a math library CANNOT (according to the standard) set errno to EDOM.

    Yes, if it conforms to the Annex F.

  9. removed
    pendingThe issue will be closed if no feedback is provided
    on Jul 7, 2026
  10. hpkfft commented on Jul 7, 2026

    @hpkfft
    ContributorAuthor

    Yeah, hmmm, indeed. I've been trying to interpret the C standard in such a way as to make the Intel math library (and the one from Sun Microsystems) compliant. I have failed. Since these libraries have been around for a while, one might guess it was the intention of the C standard to allow their atan(0,0) behavior. But that's just a guess. Regardless, I think the C standard could be improved to make the implications of Annex F clearer.

  11. skirpichev commented on Jul 7, 2026

    @skirpichev
    Member

    BTW, this issue should be reported to Intel.

  12. hpkfft commented on Jul 7, 2026

    @hpkfft
    ContributorAuthor

    this issue should be reported to Intel

    I've reported it unofficially. (I used to work in the numerics team at Intel.)

  13. hpkfft commented on Jul 8, 2026

    @hpkfft
    ContributorAuthor

    The math library in musl libc follows Annex F, and I confirmed (using gcc) that __STDC_IEC_559__ is defined.
    Musl does not provide errno based error handling; math_errhandling is MATH_ERREXCEPT.

  14. added 2 commits that reference this issue on Jul 20, 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

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions