]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-144173: fix flaky test_complex.test_truediv() (GH-144355) (#145767)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 10 Mar 2026 17:05:07 +0000 (18:05 +0100)
committerGitHub <noreply@github.com>
Tue, 10 Mar 2026 17:05:07 +0000 (17:05 +0000)
gh-144173: fix flaky test_complex.test_truediv() (GH-144355)

Previously, component-wise relative error bound was tested.  However,
such bound can't exist already for complex multiplication as one can be
used to perform subtraction of floating-point numbers, e.g. x and y for
z0=1+1j and z1=x+yj.

```pycon
>>> x, y = 1e-9+1j, 1+1j
>>> a = x*y*y.conjugate()/2;a
(1.0000000272292198e-09+1j)
>>> b = x*(y*y.conjugate()/2);b
(1e-09+1j)
>>> b == x
True
>>> (a.real-b.real)/math.ulp(b.real)
131672427.0
```
(cherry picked from commit c4333a12708a917d1cfb6418c04be45793ecc392)

Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
Lib/test/test_complex.py

index 6ff1a8ab29d0d66d062a54c8e08f9bda170aff03..af4eba5451ba196bff38fd4edd4063155fbe7df0 100644 (file)
@@ -62,8 +62,8 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
             else:
                 unittest.TestCase.assertAlmostEqual(self, a, b)
 
-    def assertCloseAbs(self, x, y, eps=1e-9):
-        """Return true iff floats x and y "are close"."""
+    def assertClose(self, x, y, eps=1e-9):
+        """Return true iff complexes x and y "are close"."""
         # put the one with larger magnitude second
         if abs(x) > abs(y):
             x, y = y, x
@@ -72,26 +72,15 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
         if x == 0:
             return abs(y) < eps
         # check that relative difference < eps
-        self.assertTrue(abs((x-y)/y) < eps)
-
-    def assertClose(self, x, y, eps=1e-9):
-        """Return true iff complexes x and y "are close"."""
-        self.assertCloseAbs(x.real, y.real, eps)
-        self.assertCloseAbs(x.imag, y.imag, eps)
+        self.assertTrue(abs(x-y)/abs(y) < eps)
 
     def check_div(self, x, y):
         """Compute complex z=x*y, and check that z/x==y and z/y==x."""
         z = x * y
-        if x != 0:
-            q = z / x
-            self.assertClose(q, y)
-            q = z.__truediv__(x)
-            self.assertClose(q, y)
-        if y != 0:
-            q = z / y
-            self.assertClose(q, x)
-            q = z.__truediv__(y)
-            self.assertClose(q, x)
+        if x:
+            self.assertClose(z / x, y)
+        if y:
+            self.assertClose(z / y, x)
 
     def test_truediv(self):
         simple_real = [float(i) for i in range(-5, 6)]
@@ -105,10 +94,20 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
         self.check_div(complex(1e200, 1e200), 1+0j)
         self.check_div(complex(1e-200, 1e-200), 1+0j)
 
+        # Smith's algorithm has several sources of inaccuracy
+        # for components of the result.  In examples below,
+        # it's cancellation of digits in computation of sum.
+        self.check_div(1e-09+1j, 1+1j)
+        self.check_div(8.289760544677449e-09+0.13257307440728516j,
+                       0.9059966714925808+0.5054864708672686j)
+
         # Just for fun.
         for i in range(100):
-            self.check_div(complex(random(), random()),
-                           complex(random(), random()))
+            x = complex(random(), random())
+            y = complex(random(), random())
+            self.check_div(x, y)
+            y = complex(1e10*y.real, y.imag)
+            self.check_div(x, y)
 
         self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j)
         self.assertRaises(TypeError, operator.truediv, 1j, None)
@@ -343,7 +342,7 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
         self.assertTrue(1j)
 
     def test_conjugate(self):
-        self.assertClose(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
+        self.assertEqual(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
 
     def test_constructor(self):
         def check(z, x, y):