GeezerVison is showing github.com — ValueError for `math.atan2(0.0, 0.0)` and `cmath.phase(0.0)` using icx · Issue #153144 · python/cpython
ValueError for math.atan2(0.0, 0.0) and cmath.phase(0.0) using icx #153144DescriptionBug 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
Activityskirpichev commented on Jul 6, 2026
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. hpkfft commented on Jul 6, 2026 ContributorAuthor More actions
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? hpkfft commented on Jul 6, 2026 ContributorAuthor More actions 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. skirpichev commented on Jul 6, 2026
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:
- "atan2(0, 0) does not raise the "invalid" floating-point exception"
but
- "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. hpkfft commented on Jul 6, 2026 ContributorAuthor More actions
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." skirpichev commented on Jul 7, 2026
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. hpkfft commented on Jul 7, 2026 ContributorAuthor More actions 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. skirpichev commented on Jul 7, 2026 BTW, this issue should be reported to Intel. hpkfft commented on Jul 7, 2026 ContributorAuthor More actions
this issue should be reported to Intel
I've reported it unofficially. (I used to work in the numerics team at Intel.) hpkfft commented on Jul 8, 2026 ContributorAuthor More actions 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. skirpichev commented on Aug 16, 2026
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|