mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-69639: Add mixed-mode rules for complex arithmetic (C-like) (GH-124829)
"Generally, mixed-mode arithmetic combining real and complex variables should be performed directly, not by first coercing the real to complex, lest the sign of zero be rendered uninformative; the same goes for combinations of pure imaginary quantities with complex variables." (c) Kahan, W: Branch cuts for complex elementary functions. This patch implements mixed-mode arithmetic rules, combining real and complex variables as specified by C standards since C99 (in particular, there is no special version for the true division with real lhs operand). Most C compilers implementing C99+ Annex G have only these special rules (without support for imaginary type, which is going to be deprecated in C2y).
This commit is contained in:
parent
dcf629213b
commit
987311d42e
15 changed files with 449 additions and 98 deletions
|
@ -126,6 +126,12 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
z = complex(0, 0) / complex(denom_real, denom_imag)
|
||||
self.assertTrue(isnan(z.real))
|
||||
self.assertTrue(isnan(z.imag))
|
||||
z = float(0) / complex(denom_real, denom_imag)
|
||||
self.assertTrue(isnan(z.real))
|
||||
self.assertTrue(isnan(z.imag))
|
||||
|
||||
self.assertComplexesAreIdentical(complex(INF, NAN) / 2,
|
||||
complex(INF, NAN))
|
||||
|
||||
self.assertComplexesAreIdentical(complex(INF, 1)/(0.0+1j),
|
||||
complex(NAN, -INF))
|
||||
|
@ -154,6 +160,39 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
self.assertComplexesAreIdentical(complex(INF, 1)/complex(1, INF),
|
||||
complex(NAN, NAN))
|
||||
|
||||
# mixed types
|
||||
self.assertEqual((1+1j)/float(2), 0.5+0.5j)
|
||||
self.assertEqual(float(1)/(1+2j), 0.2-0.4j)
|
||||
self.assertEqual(float(1)/(-1+2j), -0.2-0.4j)
|
||||
self.assertEqual(float(1)/(1-2j), 0.2+0.4j)
|
||||
self.assertEqual(float(1)/(2+1j), 0.4-0.2j)
|
||||
self.assertEqual(float(1)/(-2+1j), -0.4-0.2j)
|
||||
self.assertEqual(float(1)/(2-1j), 0.4+0.2j)
|
||||
|
||||
self.assertComplexesAreIdentical(INF/(1+0j),
|
||||
complex(INF, NAN))
|
||||
self.assertComplexesAreIdentical(INF/(0.0+1j),
|
||||
complex(NAN, -INF))
|
||||
self.assertComplexesAreIdentical(INF/complex(2**1000, 2**-1000),
|
||||
complex(INF, NAN))
|
||||
self.assertComplexesAreIdentical(INF/complex(NAN, NAN),
|
||||
complex(NAN, NAN))
|
||||
|
||||
self.assertComplexesAreIdentical(float(1)/complex(INF, INF), (0.0-0j))
|
||||
self.assertComplexesAreIdentical(float(1)/complex(INF, -INF), (0.0+0j))
|
||||
self.assertComplexesAreIdentical(float(1)/complex(-INF, INF),
|
||||
complex(-0.0, -0.0))
|
||||
self.assertComplexesAreIdentical(float(1)/complex(-INF, -INF),
|
||||
complex(-0.0, 0))
|
||||
self.assertComplexesAreIdentical(float(1)/complex(INF, NAN),
|
||||
complex(0.0, -0.0))
|
||||
self.assertComplexesAreIdentical(float(1)/complex(-INF, NAN),
|
||||
complex(-0.0, -0.0))
|
||||
self.assertComplexesAreIdentical(float(1)/complex(NAN, INF),
|
||||
complex(0.0, -0.0))
|
||||
self.assertComplexesAreIdentical(float(INF)/complex(NAN, INF),
|
||||
complex(NAN, NAN))
|
||||
|
||||
def test_truediv_zero_division(self):
|
||||
for a, b in ZERO_DIVISION:
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
|
@ -224,6 +263,10 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
def test_add(self):
|
||||
self.assertEqual(1j + int(+1), complex(+1, 1))
|
||||
self.assertEqual(1j + int(-1), complex(-1, 1))
|
||||
self.assertComplexesAreIdentical(complex(-0.0, -0.0) + (-0.0),
|
||||
complex(-0.0, -0.0))
|
||||
self.assertComplexesAreIdentical((-0.0) + complex(-0.0, -0.0),
|
||||
complex(-0.0, -0.0))
|
||||
self.assertRaises(OverflowError, operator.add, 1j, 10**1000)
|
||||
self.assertRaises(TypeError, operator.add, 1j, None)
|
||||
self.assertRaises(TypeError, operator.add, None, 1j)
|
||||
|
@ -231,6 +274,14 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
def test_sub(self):
|
||||
self.assertEqual(1j - int(+1), complex(-1, 1))
|
||||
self.assertEqual(1j - int(-1), complex(1, 1))
|
||||
self.assertComplexesAreIdentical(complex(-0.0, -0.0) - 0.0,
|
||||
complex(-0.0, -0.0))
|
||||
self.assertComplexesAreIdentical(-0.0 - complex(0.0, 0.0),
|
||||
complex(-0.0, -0.0))
|
||||
self.assertComplexesAreIdentical(complex(1, 2) - complex(2, 1),
|
||||
complex(-1, 1))
|
||||
self.assertComplexesAreIdentical(complex(2, 1) - complex(1, 2),
|
||||
complex(1, -1))
|
||||
self.assertRaises(OverflowError, operator.sub, 1j, 10**1000)
|
||||
self.assertRaises(TypeError, operator.sub, 1j, None)
|
||||
self.assertRaises(TypeError, operator.sub, None, 1j)
|
||||
|
@ -238,6 +289,12 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
def test_mul(self):
|
||||
self.assertEqual(1j * int(20), complex(0, 20))
|
||||
self.assertEqual(1j * int(-1), complex(0, -1))
|
||||
for c, r in [(2, complex(INF, 2)), (INF, complex(INF, INF)),
|
||||
(0, complex(NAN, 0)), (-0.0, complex(NAN, -0.0)),
|
||||
(NAN, complex(NAN, NAN))]:
|
||||
with self.subTest(c=c, r=r):
|
||||
self.assertComplexesAreIdentical(complex(INF, 1) * c, r)
|
||||
self.assertComplexesAreIdentical(c * complex(INF, 1), r)
|
||||
self.assertRaises(OverflowError, operator.mul, 1j, 10**1000)
|
||||
self.assertRaises(TypeError, operator.mul, 1j, None)
|
||||
self.assertRaises(TypeError, operator.mul, None, 1j)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue