Move test_math tests (GH-18098)
testPerm() and testComb() belong to MathTests, not to IsCloseTests(). test_nextafter() and test_ulp() now use assertIsNaN().
This commit is contained in:
parent
629023c05b
commit
59e2d26b25
|
@ -1746,212 +1746,6 @@ class MathTests(unittest.TestCase):
|
|||
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 @@ class IsCloseTests(unittest.TestCase):
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue