]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-144173: fix flaky test_complex.test_truediv() (#144355)
authorSergey B Kirpichev <skirpichev@gmail.com>
Tue, 10 Mar 2026 16:40:51 +0000 (19:40 +0300)
committerGitHub <noreply@github.com>
Tue, 10 Mar 2026 16:40:51 +0000 (17:40 +0100)
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
```

Lib/test/test_complex.py

index 0c7e7341f13d4ea12e0f3507fe329ddc8540e666..bee2aceb1870276f6660e1080c3eabab26917f2f 100644 (file)
@@ -72,8 +72,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
@@ -82,26 +82,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)]
@@ -115,10 +104,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)
@@ -454,7 +453,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):