Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-119372: recover inf's and zeros in _Py_c_quot #119457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Lib/test/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ def assertFloatsAreIdentical(self, x, y):
msg += ': zeros have different signs'
self.fail(msg.format(x, y))

def assertComplexesAreIdentical(self, x, y):
self.assertFloatsAreIdentical(x.real, y.real)
self.assertFloatsAreIdentical(x.imag, y.imag)

def assertClose(self, x, y, eps=1e-9):
"""Return true iff complexes x and y "are close"."""
self.assertCloseAbs(x.real, y.real, eps)
Expand Down Expand Up @@ -139,6 +143,33 @@ def test_truediv(self):
self.assertTrue(isnan(z.real))
self.assertTrue(isnan(z.imag))

self.assertComplexesAreIdentical(complex(INF, 1)/(0.0+1j),
complex(NAN, -INF))

# test recover of infs if numerator has infs and denominator is finite
self.assertComplexesAreIdentical(complex(INF, -INF)/(1+0j),
complex(INF, -INF))
self.assertComplexesAreIdentical(complex(INF, INF)/(0.0+1j),
complex(INF, -INF))
self.assertComplexesAreIdentical(complex(NAN, INF)/complex(2**1000, 2**-1000),
complex(INF, INF))
self.assertComplexesAreIdentical(complex(INF, NAN)/complex(2**1000, 2**-1000),
complex(INF, -INF))

# test recover of zeros if denominator is infinite
self.assertComplexesAreIdentical((1+1j)/complex(INF, INF), (0.0+0j))
self.assertComplexesAreIdentical((1+1j)/complex(INF, -INF), (0.0+0j))
self.assertComplexesAreIdentical((1+1j)/complex(-INF, INF),
complex(0.0, -0.0))
self.assertComplexesAreIdentical((1+1j)/complex(-INF, -INF),
complex(-0.0, 0))
self.assertComplexesAreIdentical((INF+1j)/complex(INF, INF),
complex(NAN, NAN))
self.assertComplexesAreIdentical(complex(1, INF)/complex(INF, INF),
complex(NAN, NAN))
self.assertComplexesAreIdentical(complex(INF, 1)/complex(1, INF),
complex(NAN, NAN))

def test_truediv_zero_division(self):
for a, b in ZERO_DIVISION:
with self.assertRaises(ZeroDivisionError):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Correct invalid corner cases in complex division (resulted in ``(nan+nanj)``
output), e.g. ``1/complex('(inf+infj)')``. Patch by Sergey B Kirpichev.
25 changes: 23 additions & 2 deletions Objects/complexobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ _Py_c_quot(Py_complex a, Py_complex b)
* numerators and denominator by whichever of {b.real, b.imag} has
* larger magnitude. The earliest reference I found was to CACM
* Algorithm 116 (Complex Division, Robert L. Smith, Stanford
* University). As usual, though, we're still ignoring all IEEE
* endcases.
* University).
*/
Py_complex r; /* the result */
const double abs_breal = b.real < 0 ? -b.real : b.real;
Expand Down Expand Up @@ -120,6 +119,28 @@ _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. See e.g.
the C11, Annex G.5.2, routine _Cdivd(). */
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 ((isinf(abs_breal) || isinf(abs_bimag))
&& 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;
}
#ifdef _M_ARM64
Expand Down
Loading