Move test_math tests (GH-18098)
testPerm() and testComb() belong to MathTests, not to IsCloseTests().
test_nextafter() and test_ulp() now use assertIsNaN().
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index e96fd74..b3301f6 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -1746,212 +1746,6 @@
self.assertEqual(type(prod([1, decimal.Decimal(2.0), 3, 4, 5, 6])),
decimal.Decimal)
- # Custom assertions.
-
- def assertIsNaN(self, value):
- if not math.isnan(value):
- self.fail("Expected a NaN, got {!r}.".format(value))
-
- def assertEqualSign(self, x, y):
- """Similar to assertEqual(), but compare also the sign.
-
- Function useful to compare signed zeros.
- """
- self.assertEqual(x, y)
- self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y))
-
- @requires_IEEE_754
- def test_nextafter(self):
- # around 2^52 and 2^63
- self.assertEqual(math.nextafter(4503599627370496.0, -INF),
- 4503599627370495.5)
- self.assertEqual(math.nextafter(4503599627370496.0, INF),
- 4503599627370497.0)
- self.assertEqual(math.nextafter(9223372036854775808.0, 0.0),
- 9223372036854774784.0)
- self.assertEqual(math.nextafter(-9223372036854775808.0, 0.0),
- -9223372036854774784.0)
-
- # around 1.0
- self.assertEqual(math.nextafter(1.0, -INF),
- float.fromhex('0x1.fffffffffffffp-1'))
- self.assertEqual(math.nextafter(1.0, INF),
- float.fromhex('0x1.0000000000001p+0'))
-
- # x == y: y is returned
- self.assertEqual(math.nextafter(2.0, 2.0), 2.0)
- self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0)
- self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0)
-
- # around 0.0
- smallest_subnormal = sys.float_info.min * sys.float_info.epsilon
- self.assertEqual(math.nextafter(+0.0, INF), smallest_subnormal)
- self.assertEqual(math.nextafter(-0.0, INF), smallest_subnormal)
- self.assertEqual(math.nextafter(+0.0, -INF), -smallest_subnormal)
- self.assertEqual(math.nextafter(-0.0, -INF), -smallest_subnormal)
- self.assertEqualSign(math.nextafter(smallest_subnormal, +0.0), +0.0)
- self.assertEqualSign(math.nextafter(-smallest_subnormal, +0.0), -0.0)
- self.assertEqualSign(math.nextafter(smallest_subnormal, -0.0), +0.0)
- self.assertEqualSign(math.nextafter(-smallest_subnormal, -0.0), -0.0)
-
- # around infinity
- largest_normal = sys.float_info.max
- self.assertEqual(math.nextafter(INF, 0.0), largest_normal)
- self.assertEqual(math.nextafter(-INF, 0.0), -largest_normal)
- self.assertEqual(math.nextafter(largest_normal, INF), INF)
- self.assertEqual(math.nextafter(-largest_normal, -INF), -INF)
-
- # NaN
- self.assertTrue(math.isnan(math.nextafter(NAN, 1.0)))
- self.assertTrue(math.isnan(math.nextafter(1.0, NAN)))
- self.assertTrue(math.isnan(math.nextafter(NAN, NAN)))
-
- @requires_IEEE_754
- def test_ulp(self):
- self.assertEqual(math.ulp(1.0), sys.float_info.epsilon)
- # use int ** int rather than float ** int to not rely on pow() accuracy
- self.assertEqual(math.ulp(2 ** 52), 1.0)
- self.assertEqual(math.ulp(2 ** 53), 2.0)
- self.assertEqual(math.ulp(2 ** 64), 4096.0)
-
- # min and max
- self.assertEqual(math.ulp(0.0),
- sys.float_info.min * sys.float_info.epsilon)
- self.assertEqual(math.ulp(FLOAT_MAX),
- FLOAT_MAX - math.nextafter(FLOAT_MAX, -INF))
-
- # special cases
- self.assertEqual(math.ulp(INF), INF)
- self.assertTrue(math.isnan(math.ulp(math.nan)))
-
- # negative number: ulp(-x) == ulp(x)
- for x in (0.0, 1.0, 2 ** 52, 2 ** 64, INF):
- with self.subTest(x=x):
- self.assertEqual(math.ulp(-x), math.ulp(x))
-
-
-class IsCloseTests(unittest.TestCase):
- isclose = math.isclose # subclasses should override this
-
- def assertIsClose(self, a, b, *args, **kwargs):
- self.assertTrue(self.isclose(a, b, *args, **kwargs),
- msg="%s and %s should be close!" % (a, b))
-
- def assertIsNotClose(self, a, b, *args, **kwargs):
- self.assertFalse(self.isclose(a, b, *args, **kwargs),
- msg="%s and %s should not be close!" % (a, b))
-
- def assertAllClose(self, examples, *args, **kwargs):
- for a, b in examples:
- self.assertIsClose(a, b, *args, **kwargs)
-
- def assertAllNotClose(self, examples, *args, **kwargs):
- for a, b in examples:
- self.assertIsNotClose(a, b, *args, **kwargs)
-
- def test_negative_tolerances(self):
- # ValueError should be raised if either tolerance is less than zero
- with self.assertRaises(ValueError):
- self.assertIsClose(1, 1, rel_tol=-1e-100)
- with self.assertRaises(ValueError):
- self.assertIsClose(1, 1, rel_tol=1e-100, abs_tol=-1e10)
-
- def test_identical(self):
- # identical values must test as close
- identical_examples = [(2.0, 2.0),
- (0.1e200, 0.1e200),
- (1.123e-300, 1.123e-300),
- (12345, 12345.0),
- (0.0, -0.0),
- (345678, 345678)]
- self.assertAllClose(identical_examples, rel_tol=0.0, abs_tol=0.0)
-
- def test_eight_decimal_places(self):
- # examples that are close to 1e-8, but not 1e-9
- eight_decimal_places_examples = [(1e8, 1e8 + 1),
- (-1e-8, -1.000000009e-8),
- (1.12345678, 1.12345679)]
- self.assertAllClose(eight_decimal_places_examples, rel_tol=1e-8)
- self.assertAllNotClose(eight_decimal_places_examples, rel_tol=1e-9)
-
- def test_near_zero(self):
- # values close to zero
- near_zero_examples = [(1e-9, 0.0),
- (-1e-9, 0.0),
- (-1e-150, 0.0)]
- # these should not be close to any rel_tol
- self.assertAllNotClose(near_zero_examples, rel_tol=0.9)
- # these should be close to abs_tol=1e-8
- self.assertAllClose(near_zero_examples, abs_tol=1e-8)
-
- def test_identical_infinite(self):
- # these are close regardless of tolerance -- i.e. they are equal
- self.assertIsClose(INF, INF)
- self.assertIsClose(INF, INF, abs_tol=0.0)
- self.assertIsClose(NINF, NINF)
- self.assertIsClose(NINF, NINF, abs_tol=0.0)
-
- def test_inf_ninf_nan(self):
- # these should never be close (following IEEE 754 rules for equality)
- not_close_examples = [(NAN, NAN),
- (NAN, 1e-100),
- (1e-100, NAN),
- (INF, NAN),
- (NAN, INF),
- (INF, NINF),
- (INF, 1.0),
- (1.0, INF),
- (INF, 1e308),
- (1e308, INF)]
- # use largest reasonable tolerance
- self.assertAllNotClose(not_close_examples, abs_tol=0.999999999999999)
-
- def test_zero_tolerance(self):
- # test with zero tolerance
- zero_tolerance_close_examples = [(1.0, 1.0),
- (-3.4, -3.4),
- (-1e-300, -1e-300)]
- self.assertAllClose(zero_tolerance_close_examples, rel_tol=0.0)
-
- zero_tolerance_not_close_examples = [(1.0, 1.000000000000001),
- (0.99999999999999, 1.0),
- (1.0e200, .999999999999999e200)]
- self.assertAllNotClose(zero_tolerance_not_close_examples, rel_tol=0.0)
-
- def test_asymmetry(self):
- # test the asymmetry example from PEP 485
- self.assertAllClose([(9, 10), (10, 9)], rel_tol=0.1)
-
- def test_integers(self):
- # test with integer values
- integer_examples = [(100000001, 100000000),
- (123456789, 123456788)]
-
- self.assertAllClose(integer_examples, rel_tol=1e-8)
- self.assertAllNotClose(integer_examples, rel_tol=1e-9)
-
- def test_decimals(self):
- # test with Decimal values
- from decimal import Decimal
-
- decimal_examples = [(Decimal('1.00000001'), Decimal('1.0')),
- (Decimal('1.00000001e-20'), Decimal('1.0e-20')),
- (Decimal('1.00000001e-100'), Decimal('1.0e-100')),
- (Decimal('1.00000001e20'), Decimal('1.0e20'))]
- self.assertAllClose(decimal_examples, rel_tol=1e-8)
- self.assertAllNotClose(decimal_examples, rel_tol=1e-9)
-
- def test_fractions(self):
- # test with Fraction values
- from fractions import Fraction
-
- fraction_examples = [
- (Fraction(1, 100000000) + 1, Fraction(1)),
- (Fraction(100000001), Fraction(100000000)),
- (Fraction(10**8 + 1, 10**28), Fraction(1, 10**20))]
- self.assertAllClose(fraction_examples, rel_tol=1e-8)
- self.assertAllNotClose(fraction_examples, rel_tol=1e-9)
-
def testPerm(self):
perm = math.perm
factorial = math.factorial
@@ -2086,6 +1880,212 @@
self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int)
self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int)
+ @requires_IEEE_754
+ def test_nextafter(self):
+ # around 2^52 and 2^63
+ self.assertEqual(math.nextafter(4503599627370496.0, -INF),
+ 4503599627370495.5)
+ self.assertEqual(math.nextafter(4503599627370496.0, INF),
+ 4503599627370497.0)
+ self.assertEqual(math.nextafter(9223372036854775808.0, 0.0),
+ 9223372036854774784.0)
+ self.assertEqual(math.nextafter(-9223372036854775808.0, 0.0),
+ -9223372036854774784.0)
+
+ # around 1.0
+ self.assertEqual(math.nextafter(1.0, -INF),
+ float.fromhex('0x1.fffffffffffffp-1'))
+ self.assertEqual(math.nextafter(1.0, INF),
+ float.fromhex('0x1.0000000000001p+0'))
+
+ # x == y: y is returned
+ self.assertEqual(math.nextafter(2.0, 2.0), 2.0)
+ self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0)
+ self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0)
+
+ # around 0.0
+ smallest_subnormal = sys.float_info.min * sys.float_info.epsilon
+ self.assertEqual(math.nextafter(+0.0, INF), smallest_subnormal)
+ self.assertEqual(math.nextafter(-0.0, INF), smallest_subnormal)
+ self.assertEqual(math.nextafter(+0.0, -INF), -smallest_subnormal)
+ self.assertEqual(math.nextafter(-0.0, -INF), -smallest_subnormal)
+ self.assertEqualSign(math.nextafter(smallest_subnormal, +0.0), +0.0)
+ self.assertEqualSign(math.nextafter(-smallest_subnormal, +0.0), -0.0)
+ self.assertEqualSign(math.nextafter(smallest_subnormal, -0.0), +0.0)
+ self.assertEqualSign(math.nextafter(-smallest_subnormal, -0.0), -0.0)
+
+ # around infinity
+ largest_normal = sys.float_info.max
+ self.assertEqual(math.nextafter(INF, 0.0), largest_normal)
+ self.assertEqual(math.nextafter(-INF, 0.0), -largest_normal)
+ self.assertEqual(math.nextafter(largest_normal, INF), INF)
+ self.assertEqual(math.nextafter(-largest_normal, -INF), -INF)
+
+ # NaN
+ self.assertIsNaN(math.nextafter(NAN, 1.0))
+ self.assertIsNaN(math.nextafter(1.0, NAN))
+ self.assertIsNaN(math.nextafter(NAN, NAN))
+
+ @requires_IEEE_754
+ def test_ulp(self):
+ self.assertEqual(math.ulp(1.0), sys.float_info.epsilon)
+ # use int ** int rather than float ** int to not rely on pow() accuracy
+ self.assertEqual(math.ulp(2 ** 52), 1.0)
+ self.assertEqual(math.ulp(2 ** 53), 2.0)
+ self.assertEqual(math.ulp(2 ** 64), 4096.0)
+
+ # min and max
+ self.assertEqual(math.ulp(0.0),
+ sys.float_info.min * sys.float_info.epsilon)
+ self.assertEqual(math.ulp(FLOAT_MAX),
+ FLOAT_MAX - math.nextafter(FLOAT_MAX, -INF))
+
+ # special cases
+ self.assertEqual(math.ulp(INF), INF)
+ self.assertIsNaN(math.ulp(math.nan))
+
+ # negative number: ulp(-x) == ulp(x)
+ for x in (0.0, 1.0, 2 ** 52, 2 ** 64, INF):
+ with self.subTest(x=x):
+ self.assertEqual(math.ulp(-x), math.ulp(x))
+
+ # Custom assertions.
+
+ def assertIsNaN(self, value):
+ if not math.isnan(value):
+ self.fail("Expected a NaN, got {!r}.".format(value))
+
+ def assertEqualSign(self, x, y):
+ """Similar to assertEqual(), but compare also the sign with copysign().
+
+ Function useful to compare signed zeros.
+ """
+ self.assertEqual(x, y)
+ self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y))
+
+
+class IsCloseTests(unittest.TestCase):
+ isclose = math.isclose # subclasses should override this
+
+ def assertIsClose(self, a, b, *args, **kwargs):
+ self.assertTrue(self.isclose(a, b, *args, **kwargs),
+ msg="%s and %s should be close!" % (a, b))
+
+ def assertIsNotClose(self, a, b, *args, **kwargs):
+ self.assertFalse(self.isclose(a, b, *args, **kwargs),
+ msg="%s and %s should not be close!" % (a, b))
+
+ def assertAllClose(self, examples, *args, **kwargs):
+ for a, b in examples:
+ self.assertIsClose(a, b, *args, **kwargs)
+
+ def assertAllNotClose(self, examples, *args, **kwargs):
+ for a, b in examples:
+ self.assertIsNotClose(a, b, *args, **kwargs)
+
+ def test_negative_tolerances(self):
+ # ValueError should be raised if either tolerance is less than zero
+ with self.assertRaises(ValueError):
+ self.assertIsClose(1, 1, rel_tol=-1e-100)
+ with self.assertRaises(ValueError):
+ self.assertIsClose(1, 1, rel_tol=1e-100, abs_tol=-1e10)
+
+ def test_identical(self):
+ # identical values must test as close
+ identical_examples = [(2.0, 2.0),
+ (0.1e200, 0.1e200),
+ (1.123e-300, 1.123e-300),
+ (12345, 12345.0),
+ (0.0, -0.0),
+ (345678, 345678)]
+ self.assertAllClose(identical_examples, rel_tol=0.0, abs_tol=0.0)
+
+ def test_eight_decimal_places(self):
+ # examples that are close to 1e-8, but not 1e-9
+ eight_decimal_places_examples = [(1e8, 1e8 + 1),
+ (-1e-8, -1.000000009e-8),
+ (1.12345678, 1.12345679)]
+ self.assertAllClose(eight_decimal_places_examples, rel_tol=1e-8)
+ self.assertAllNotClose(eight_decimal_places_examples, rel_tol=1e-9)
+
+ def test_near_zero(self):
+ # values close to zero
+ near_zero_examples = [(1e-9, 0.0),
+ (-1e-9, 0.0),
+ (-1e-150, 0.0)]
+ # these should not be close to any rel_tol
+ self.assertAllNotClose(near_zero_examples, rel_tol=0.9)
+ # these should be close to abs_tol=1e-8
+ self.assertAllClose(near_zero_examples, abs_tol=1e-8)
+
+ def test_identical_infinite(self):
+ # these are close regardless of tolerance -- i.e. they are equal
+ self.assertIsClose(INF, INF)
+ self.assertIsClose(INF, INF, abs_tol=0.0)
+ self.assertIsClose(NINF, NINF)
+ self.assertIsClose(NINF, NINF, abs_tol=0.0)
+
+ def test_inf_ninf_nan(self):
+ # these should never be close (following IEEE 754 rules for equality)
+ not_close_examples = [(NAN, NAN),
+ (NAN, 1e-100),
+ (1e-100, NAN),
+ (INF, NAN),
+ (NAN, INF),
+ (INF, NINF),
+ (INF, 1.0),
+ (1.0, INF),
+ (INF, 1e308),
+ (1e308, INF)]
+ # use largest reasonable tolerance
+ self.assertAllNotClose(not_close_examples, abs_tol=0.999999999999999)
+
+ def test_zero_tolerance(self):
+ # test with zero tolerance
+ zero_tolerance_close_examples = [(1.0, 1.0),
+ (-3.4, -3.4),
+ (-1e-300, -1e-300)]
+ self.assertAllClose(zero_tolerance_close_examples, rel_tol=0.0)
+
+ zero_tolerance_not_close_examples = [(1.0, 1.000000000000001),
+ (0.99999999999999, 1.0),
+ (1.0e200, .999999999999999e200)]
+ self.assertAllNotClose(zero_tolerance_not_close_examples, rel_tol=0.0)
+
+ def test_asymmetry(self):
+ # test the asymmetry example from PEP 485
+ self.assertAllClose([(9, 10), (10, 9)], rel_tol=0.1)
+
+ def test_integers(self):
+ # test with integer values
+ integer_examples = [(100000001, 100000000),
+ (123456789, 123456788)]
+
+ self.assertAllClose(integer_examples, rel_tol=1e-8)
+ self.assertAllNotClose(integer_examples, rel_tol=1e-9)
+
+ def test_decimals(self):
+ # test with Decimal values
+ from decimal import Decimal
+
+ decimal_examples = [(Decimal('1.00000001'), Decimal('1.0')),
+ (Decimal('1.00000001e-20'), Decimal('1.0e-20')),
+ (Decimal('1.00000001e-100'), Decimal('1.0e-100')),
+ (Decimal('1.00000001e20'), Decimal('1.0e20'))]
+ self.assertAllClose(decimal_examples, rel_tol=1e-8)
+ self.assertAllNotClose(decimal_examples, rel_tol=1e-9)
+
+ def test_fractions(self):
+ # test with Fraction values
+ from fractions import Fraction
+
+ fraction_examples = [
+ (Fraction(1, 100000000) + 1, Fraction(1)),
+ (Fraction(100000001), Fraction(100000000)),
+ (Fraction(10**8 + 1, 10**28), Fraction(1, 10**20))]
+ self.assertAllClose(fraction_examples, rel_tol=1e-8)
+ self.assertAllNotClose(fraction_examples, rel_tol=1e-9)
+
def test_main():
from doctest import DocFileSuite