You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Invalid corner cases (resulting in nan+nanj) in complex division #119372
It seems, there are not so much such cases (i.e. when the numerator is finite and the denominator has infinite and infinite/nan components, or if the numerator has infinite components and the denominator has zeros). Following patch (mostly literally taken from the C11 Annex G.5.1 _Cdivd()'s example, except for the denom == 0.0 case) should fix the issue:
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index b3d57b8337..9041cbb8ae 100644
--- a/Objects/complexobject.c+++ b/Objects/complexobject.c@@ -122,6 +122,27 @@ _Py_c_quot(Py_complex a, Py_complex b)
/* At least one of b.real or b.imag is a NaN */
r.real = r.imag = Py_NAN;
}
++ /* Recover infinities and zeros that computed as nan+nanj */+ if (isnan(r.real) && isnan(r.imag)) {+ if ((isinf(a.real) || isinf(a.imag))+ && isfinite(b.real) && isfinite(b.imag))+ {+ const double x = copysign(isinf(a.real) ? 1.0 : 0.0, a.real);+ const double y = copysign(isinf(a.imag) ? 1.0 : 0.0, a.imag);+ r.real = Py_INFINITY * (x*b.real + y*b.imag);+ r.imag = Py_INFINITY * (y*b.real - x*b.imag);+ }+ else if ((fmax(abs_breal, abs_bimag) == Py_INFINITY)+ && isfinite(a.real) && isfinite(a.imag))+ {+ const double x = copysign(isinf(b.real) ? 1.0 : 0.0, b.real);+ const double y = copysign(isinf(b.imag) ? 1.0 : 0.0, b.imag);+ r.real = 0.0 * (a.real*x + a.imag*y);+ r.imag = 0.0 * (a.imag*x - a.real*y);+ }+ }+
return r;
}
Perhaps, we could also clear ending remark in _Py_c_quot() comment:
I agree. If the numerator is finite and the denominator is infinite, the result should be zero. If the numerator is also infinite or contains a NaN, the result should contain a NaN (but not always both component should be NaN). Do you mind to create a PR? Pay attention to the sign of zeros, in some cases it can be clearly defined.
Please note that this issue was restricted to true division and (nan+nanj) output.
1/(cmath.inf + cmath.infj)
That's similar to my example: CPython's complex arithmetic has no mixed-mode rules (e.g. for float x complex), so it's an equivalent of (1+0j)/(cmath.inf + cmath.infj). Should be 0j.
cmath.inf * 1j
Seems to be valid: inf * 1j == (inf+0j)*(0+1j)=(inf*0-0*1)+(inf*1+0*0)j=(nan+infj). You might expect infj output, per C11 Annex G, but this will imply mentioned above mixed-mode rules for complex arithmetic (and special imaginary data type, e.g. for 1j).
But we have some cases, when CPython math give (nan+nanj) for multiplication and C code - something different. If this worth an issue - it should be a separate one.
Activity
eendebakpt commentedon May 22, 2024
I can confirm the behavior described above. Some similar cases:
But numpy shows the same behaviour as current cpython main
serhiy-storchaka commentedon May 22, 2024
I agree. If the numerator is finite and the denominator is infinite, the result should be zero. If the numerator is also infinite or contains a NaN, the result should contain a NaN (but not always both component should be NaN). Do you mind to create a PR? Pay attention to the sign of zeros, in some cases it can be clearly defined.
skirpichev commentedon May 22, 2024
Please note that this issue was restricted to true division and
(nan+nanj)output.That's similar to my example: CPython's complex arithmetic has no mixed-mode rules (e.g. for float x complex), so it's an equivalent of
(1+0j)/(cmath.inf + cmath.infj). Should be0j.Seems to be valid:
inf * 1j == (inf+0j)*(0+1j)=(inf*0-0*1)+(inf*1+0*0)j=(nan+infj). You might expectinfjoutput, per C11 Annex G, but this will imply mentioned above mixed-mode rules for complex arithmetic (and special imaginary data type, e.g. for1j).But we have some cases, when CPython math give
(nan+nanj)for multiplication and C code - something different. If this worth an issue - it should be a separate one.an example
I guess, implementation copied from CPython.
@serhiy-storchaka, yes, see above diff.
pythongh-119372: recover inf's and zeros in _Py_c_quot
skirpichev commentedon May 23, 2024
FYI, PR #119457 is ready for review.
pythongh-119372: Recover inf's and zeros in _Py_c_quot/_Py_c_quot_real
pythongh-119372: Recover inf's and zeros in _Py_c_quot/_Py_c_quot_real
pythongh-119372: Recover inf's and zeros in _Py_c_quot/_Py_c_quot_real
gh-119372: Recover inf's and zeros in _Py_c_quot (GH-119457)
pythongh-119372: Recover inf's and zeros in _Py_c_quot (pythonGH-119457)
pythongh-119372: Recover inf's and zeros in _Py_c_quot (pythonGH-119457)
pythongh-119372: Recover inf's and zeros in _Py_c_quot (pythonGH-119457)