Skip to content

Use subTest() in math.fma() tests #131125

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 1 commit into from
Mar 12, 2025
Merged
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
137 changes: 73 additions & 64 deletions Lib/test/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -2693,9 +2693,10 @@ def test_fma_nan_results(self):

# If any input is a NaN, the result should be a NaN, too.
for a, b in itertools.product(values, repeat=2):
self.assertIsNaN(math.fma(math.nan, a, b))
self.assertIsNaN(math.fma(a, math.nan, b))
self.assertIsNaN(math.fma(a, b, math.nan))
with self.subTest(a=a, b=b):
self.assertIsNaN(math.fma(math.nan, a, b))
self.assertIsNaN(math.fma(a, math.nan, b))
self.assertIsNaN(math.fma(a, b, math.nan))

def test_fma_infinities(self):
# Cases involving infinite inputs or results.
Expand All @@ -2707,57 +2708,62 @@ def test_fma_infinities(self):
for c in non_nans:
for infinity in [math.inf, -math.inf]:
for zero in [0.0, -0.0]:
with self.assertRaises(ValueError):
math.fma(infinity, zero, c)
with self.assertRaises(ValueError):
math.fma(zero, infinity, c)
with self.subTest(c=c, infinity=infinity, zero=zero):
with self.assertRaises(ValueError):
math.fma(infinity, zero, c)
with self.assertRaises(ValueError):
math.fma(zero, infinity, c)

# ValueError when a*b and c both infinite of opposite signs.
for b in positives:
with self.assertRaises(ValueError):
math.fma(math.inf, b, -math.inf)
with self.assertRaises(ValueError):
math.fma(math.inf, -b, math.inf)
with self.assertRaises(ValueError):
math.fma(-math.inf, -b, -math.inf)
with self.assertRaises(ValueError):
math.fma(-math.inf, b, math.inf)
with self.assertRaises(ValueError):
math.fma(b, math.inf, -math.inf)
with self.assertRaises(ValueError):
math.fma(-b, math.inf, math.inf)
with self.assertRaises(ValueError):
math.fma(-b, -math.inf, -math.inf)
with self.assertRaises(ValueError):
math.fma(b, -math.inf, math.inf)
with self.subTest(b=b):
with self.assertRaises(ValueError):
math.fma(math.inf, b, -math.inf)
with self.assertRaises(ValueError):
math.fma(math.inf, -b, math.inf)
with self.assertRaises(ValueError):
math.fma(-math.inf, -b, -math.inf)
with self.assertRaises(ValueError):
math.fma(-math.inf, b, math.inf)
with self.assertRaises(ValueError):
math.fma(b, math.inf, -math.inf)
with self.assertRaises(ValueError):
math.fma(-b, math.inf, math.inf)
with self.assertRaises(ValueError):
math.fma(-b, -math.inf, -math.inf)
with self.assertRaises(ValueError):
math.fma(b, -math.inf, math.inf)

# Infinite result when a*b and c both infinite of the same sign.
for b in positives:
self.assertEqual(math.fma(math.inf, b, math.inf), math.inf)
self.assertEqual(math.fma(math.inf, -b, -math.inf), -math.inf)
self.assertEqual(math.fma(-math.inf, -b, math.inf), math.inf)
self.assertEqual(math.fma(-math.inf, b, -math.inf), -math.inf)
self.assertEqual(math.fma(b, math.inf, math.inf), math.inf)
self.assertEqual(math.fma(-b, math.inf, -math.inf), -math.inf)
self.assertEqual(math.fma(-b, -math.inf, math.inf), math.inf)
self.assertEqual(math.fma(b, -math.inf, -math.inf), -math.inf)
with self.subTest(b=b):
self.assertEqual(math.fma(math.inf, b, math.inf), math.inf)
self.assertEqual(math.fma(math.inf, -b, -math.inf), -math.inf)
self.assertEqual(math.fma(-math.inf, -b, math.inf), math.inf)
self.assertEqual(math.fma(-math.inf, b, -math.inf), -math.inf)
self.assertEqual(math.fma(b, math.inf, math.inf), math.inf)
self.assertEqual(math.fma(-b, math.inf, -math.inf), -math.inf)
self.assertEqual(math.fma(-b, -math.inf, math.inf), math.inf)
self.assertEqual(math.fma(b, -math.inf, -math.inf), -math.inf)

# Infinite result when a*b finite, c infinite.
for a, b in itertools.product(finites, finites):
self.assertEqual(math.fma(a, b, math.inf), math.inf)
self.assertEqual(math.fma(a, b, -math.inf), -math.inf)
with self.subTest(b=b):
self.assertEqual(math.fma(a, b, math.inf), math.inf)
self.assertEqual(math.fma(a, b, -math.inf), -math.inf)

# Infinite result when a*b infinite, c finite.
for b, c in itertools.product(positives, finites):
self.assertEqual(math.fma(math.inf, b, c), math.inf)
self.assertEqual(math.fma(-math.inf, b, c), -math.inf)
self.assertEqual(math.fma(-math.inf, -b, c), math.inf)
self.assertEqual(math.fma(math.inf, -b, c), -math.inf)
with self.subTest(b=b, c=c):
self.assertEqual(math.fma(math.inf, b, c), math.inf)
self.assertEqual(math.fma(-math.inf, b, c), -math.inf)
self.assertEqual(math.fma(-math.inf, -b, c), math.inf)
self.assertEqual(math.fma(math.inf, -b, c), -math.inf)

self.assertEqual(math.fma(b, math.inf, c), math.inf)
self.assertEqual(math.fma(b, -math.inf, c), -math.inf)
self.assertEqual(math.fma(-b, -math.inf, c), math.inf)
self.assertEqual(math.fma(-b, math.inf, c), -math.inf)
self.assertEqual(math.fma(b, math.inf, c), math.inf)
self.assertEqual(math.fma(b, -math.inf, c), -math.inf)
self.assertEqual(math.fma(-b, -math.inf, c), math.inf)
self.assertEqual(math.fma(-b, math.inf, c), -math.inf)

# gh-73468: On some platforms, libc fma() doesn't implement IEE 754-2008
# properly: it doesn't use the right sign when the result is zero.
Expand All @@ -2770,23 +2776,24 @@ def test_fma_zero_result(self):

# Zero results from exact zero inputs.
for b in nonnegative_finites:
self.assertIsPositiveZero(math.fma(0.0, b, 0.0))
self.assertIsPositiveZero(math.fma(0.0, b, -0.0))
self.assertIsNegativeZero(math.fma(0.0, -b, -0.0))
self.assertIsPositiveZero(math.fma(0.0, -b, 0.0))
self.assertIsPositiveZero(math.fma(-0.0, -b, 0.0))
self.assertIsPositiveZero(math.fma(-0.0, -b, -0.0))
self.assertIsNegativeZero(math.fma(-0.0, b, -0.0))
self.assertIsPositiveZero(math.fma(-0.0, b, 0.0))

self.assertIsPositiveZero(math.fma(b, 0.0, 0.0))
self.assertIsPositiveZero(math.fma(b, 0.0, -0.0))
self.assertIsNegativeZero(math.fma(-b, 0.0, -0.0))
self.assertIsPositiveZero(math.fma(-b, 0.0, 0.0))
self.assertIsPositiveZero(math.fma(-b, -0.0, 0.0))
self.assertIsPositiveZero(math.fma(-b, -0.0, -0.0))
self.assertIsNegativeZero(math.fma(b, -0.0, -0.0))
self.assertIsPositiveZero(math.fma(b, -0.0, 0.0))
with self.subTest(b=b):
self.assertIsPositiveZero(math.fma(0.0, b, 0.0))
self.assertIsPositiveZero(math.fma(0.0, b, -0.0))
self.assertIsNegativeZero(math.fma(0.0, -b, -0.0))
self.assertIsPositiveZero(math.fma(0.0, -b, 0.0))
self.assertIsPositiveZero(math.fma(-0.0, -b, 0.0))
self.assertIsPositiveZero(math.fma(-0.0, -b, -0.0))
self.assertIsNegativeZero(math.fma(-0.0, b, -0.0))
self.assertIsPositiveZero(math.fma(-0.0, b, 0.0))

self.assertIsPositiveZero(math.fma(b, 0.0, 0.0))
self.assertIsPositiveZero(math.fma(b, 0.0, -0.0))
self.assertIsNegativeZero(math.fma(-b, 0.0, -0.0))
self.assertIsPositiveZero(math.fma(-b, 0.0, 0.0))
self.assertIsPositiveZero(math.fma(-b, -0.0, 0.0))
self.assertIsPositiveZero(math.fma(-b, -0.0, -0.0))
self.assertIsNegativeZero(math.fma(b, -0.0, -0.0))
self.assertIsPositiveZero(math.fma(b, -0.0, 0.0))

# Exact zero result from nonzero inputs.
self.assertIsPositiveZero(math.fma(2.0, 2.0, -4.0))
Expand Down Expand Up @@ -2892,12 +2899,14 @@ def test_random(self):
'0x1.f5467b1911fd6p-2', '0x1.b5cee3225caa5p-1'),
]
for a_hex, b_hex, c_hex, expected_hex in test_values:
a = float.fromhex(a_hex)
b = float.fromhex(b_hex)
c = float.fromhex(c_hex)
expected = float.fromhex(expected_hex)
self.assertEqual(math.fma(a, b, c), expected)
self.assertEqual(math.fma(b, a, c), expected)
with self.subTest(a_hex=a_hex, b_hex=b_hex, c_hex=c_hex,
expected_hex=expected_hex):
a = float.fromhex(a_hex)
b = float.fromhex(b_hex)
c = float.fromhex(c_hex)
expected = float.fromhex(expected_hex)
self.assertEqual(math.fma(a, b, c), expected)
self.assertEqual(math.fma(b, a, c), expected)

# Custom assertions.
def assertIsNaN(self, value):
Expand Down
Loading