@@ -159,6 +159,12 @@ class MyFloat:
159
159
def __float__ (self ):
160
160
return 0.6
161
161
162
+ class MyInt (object ):
163
+ def __init__ (self , value ):
164
+ self .value = value
165
+ def __int__ (self ):
166
+ return self .value
167
+
162
168
class MathTests (unittest .TestCase ):
163
169
164
170
def ftest (self , name , got , expected , ulp_tol = 5 , abs_tol = 0.0 ):
@@ -482,6 +488,11 @@ def test_basic_copysign(self):
482
488
self .assertEqual (math .copysign (999999999999999999999.1 , 1 ), 999999999999999999999.1 )
483
489
self .assertRaises (TypeError , math .copysign , 'hello' , 1 )
484
490
self .assertRaises (TypeError , math .copysign , 1 , 'hello' )
491
+
492
+ self .assertEqual (math .copysign (MyFloat (), 1 ), 0.6 )
493
+ self .assertEqual (math .copysign (MyFloat (), - 1 ), - 0.6 )
494
+ self .assertEqual (math .copysign (1.2 , MyFloat ()), 1.2 )
495
+ self .assertEqual (math .copysign (MyFloat (), MyFloat ()), 0.6 )
485
496
486
497
def test_inf_copysign (self ):
487
498
self .assertEqual (math .copysign (1.0 , float ('inf' )), 1.0 )
@@ -928,6 +939,8 @@ def test_fabs(self):
928
939
self .assertEqual (math .fabs (True ), 1.0 )
929
940
self .assertEqual (math .fabs (False ), 0.0 )
930
941
942
+ self .assertEqual (math .fabs (MyFloat ()), 0.6 )
943
+
931
944
def test_factorial (self ):
932
945
self .assertRaises (ValueError , math .factorial , float ('nan' ))
933
946
self .assertRaises (ValueError , math .factorial , float ('inf' ))
@@ -953,6 +966,12 @@ def test_factorial(self):
953
966
self .assertEqual (math .factorial (13 ), 6227020800 )
954
967
self .assertEqual (math .factorial (30 ), 265252859812191058636308480000000 )
955
968
self .assertRaises (ValueError , math .factorial , - 11.1 )
969
+
970
+ self .assertEqual (math .factorial (MyInt (4 )), 24 )
971
+ self .assertEqual (math .factorial (MyInt (True )), 1 )
972
+ self .assertRaises (TypeError , math .factorial , MyIndexable (4 ))
973
+ self .assertRaises (TypeError , math .factorial , MyFloat ())
974
+ self .assertRaises (TypeError , math .factorial , MyInt (0.6 ))
956
975
957
976
def testGcd (self ):
958
977
if (sys .version_info .major >= 3 and sys .version_info .minor >= 5 ):
@@ -1038,6 +1057,15 @@ class TestNoFloor:
1038
1057
self .assertEqual (math .floor (2432902008176640000999 ), 2432902008176640000999 )
1039
1058
self .assertEqual (math .floor (2432902008176640000999.99 ), 2432902008176640000999.99 )
1040
1059
1060
+ self .assertEqual (math .floor (MyFloat ()), 0 )
1061
+
1062
+ class MyFloorFloat ():
1063
+ def __floor__ (self ):
1064
+ return 12
1065
+ def __float (self ):
1066
+ return 112
1067
+ self .assertEqual (math .floor (MyFloorFloat ()), 12 )
1068
+
1041
1069
def test_fmod (self ):
1042
1070
self .assertRaises (TypeError , math .fmod )
1043
1071
self .ftest ('fmod(10, 1)' , math .fmod (10 , 1 ), 0.0 )
@@ -1103,6 +1131,9 @@ def test_fmod(self):
1103
1131
self .assertEqual (math .fmod (2432902008176640000999 , 12.12 ), 10.396369527944033 )
1104
1132
self .assertEqual (math .fmod (- 1e-100 , 1e100 ), - 1e-100 )
1105
1133
1134
+ self .assertEqual (math .fmod (MyFloat (), 1 ), 0.6 )
1135
+ self .assertEqual (math .fmod (MyFloat (), MyFloat ()), 0. )
1136
+
1106
1137
def testExp (self ):
1107
1138
self .assertRaises (TypeError , math .exp )
1108
1139
self .ftest ('exp(-1)' , math .exp (- 1 ), 1 / math .e )
@@ -1174,6 +1205,7 @@ def getY():
1174
1205
testfrexp ('frexp(Y(11.11))' , math .frexp (Y (11.11 )), (0.694375 , 4 ))
1175
1206
testfrexp ('frexp(2**1023)' , math .frexp (2 ** 1023 ), (0.5 , 1024 ))
1176
1207
self .assertRaises (OverflowError , math .frexp , 2 ** 1024 )
1208
+ testfrexp ('frexp(MyFloat())' , math .frexp (MyFloat ()), (0.6 , 0 ))
1177
1209
1178
1210
def test_ldexp (self ):
1179
1211
self .assertRaises (TypeError , math .ldexp )
@@ -1223,6 +1255,13 @@ class II(int):
1223
1255
self .assertRaises (TypeError , math .ldexp , 1 , 'Hello' )
1224
1256
self .assertEqual (math .ldexp (7589167167882033 , - 48 ), 26.962138008038156 )
1225
1257
1258
+ self .assertRaises (TypeError , math .ldexp , 1 , MyIndexable (2 ))
1259
+ self .assertRaises (TypeError , math .ldexp , 1 , MyInt (2 ))
1260
+ self .assertRaises (TypeError , math .ldexp , 1 , MyFloat ())
1261
+ self .assertEqual (math .ldexp (0.1 , True ), 0.2 )
1262
+ self .assertEqual (math .ldexp (MyFloat (),True ), 1.2 )
1263
+ self .assertRaises (TypeError , math .ldexp , MyInt (2 ), MyFloat ())
1264
+
1226
1265
def test_trunc (self ):
1227
1266
self .assertEqual (math .trunc (1 ), 1 )
1228
1267
self .assertEqual (math .trunc (- 1 ), - 1 )
@@ -1595,3 +1634,140 @@ def msum(iterable):
1595
1634
1596
1635
self .assertRaises (ValueError , math .fsum , [1. , 2 , INF , NINF ])
1597
1636
self .assertEqual (math .fsum ([1. , 2 , INF , INF ]), INF )
1637
+
1638
+ class IsCloseTests (unittest .TestCase ):
1639
+ isclose = staticmethod (math .isclose ) # sublcasses should override this
1640
+
1641
+ def assertIsClose (self , a , b , * args , ** kwargs ):
1642
+ self .assertTrue (self .isclose (a , b , * args , ** kwargs ),
1643
+ msg = "%s and %s should be close!" % (a , b ))
1644
+
1645
+ def assertIsNotClose (self , a , b , * args , ** kwargs ):
1646
+ self .assertFalse (self .isclose (a , b , * args , ** kwargs ),
1647
+ msg = "%s and %s should not be close!" % (a , b ))
1648
+
1649
+ def assertAllClose (self , examples , * args , ** kwargs ):
1650
+ for a , b in examples :
1651
+ self .assertIsClose (a , b , * args , ** kwargs )
1652
+
1653
+ def assertAllNotClose (self , examples , * args , ** kwargs ):
1654
+ for a , b in examples :
1655
+ self .assertIsNotClose (a , b , * args , ** kwargs )
1656
+
1657
+ def test_negative_tolerances (self ):
1658
+ # ValueError should be raised if either tolerance is less than zero
1659
+ with self .assertRaises (ValueError ):
1660
+ self .assertIsClose (1 , 1 , rel_tol = - 1e-100 )
1661
+ with self .assertRaises (ValueError ):
1662
+ self .assertIsClose (1 , 1 , rel_tol = 1e-100 , abs_tol = - 1e10 )
1663
+
1664
+ def test_identical (self ):
1665
+ # identical values must test as close
1666
+ identical_examples = [(2.0 , 2.0 ),
1667
+ (0.1e200 , 0.1e200 ),
1668
+ (1.123e-300 , 1.123e-300 ),
1669
+ (12345 , 12345.0 ),
1670
+ (0.0 , - 0.0 ),
1671
+ (345678 , 345678 )]
1672
+ self .assertAllClose (identical_examples , rel_tol = 0.0 , abs_tol = 0.0 )
1673
+
1674
+ def test_eight_decimal_places (self ):
1675
+ # examples that are close to 1e-8, but not 1e-9
1676
+ eight_decimal_places_examples = [(1e8 , 1e8 + 1 ),
1677
+ (- 1e-8 , - 1.000000009e-8 ),
1678
+ (1.12345678 , 1.12345679 )]
1679
+ self .assertAllClose (eight_decimal_places_examples , rel_tol = 1e-8 )
1680
+ self .assertAllNotClose (eight_decimal_places_examples , rel_tol = 1e-9 )
1681
+
1682
+ def test_near_zero (self ):
1683
+ # values close to zero
1684
+ near_zero_examples = [(1e-9 , 0.0 ),
1685
+ (- 1e-9 , 0.0 ),
1686
+ (- 1e-150 , 0.0 )]
1687
+ # these should not be close to any rel_tol
1688
+ self .assertAllNotClose (near_zero_examples , rel_tol = 0.9 )
1689
+ # these should be close to abs_tol=1e-8
1690
+ self .assertAllClose (near_zero_examples , abs_tol = 1e-8 )
1691
+
1692
+ def test_identical_infinite (self ):
1693
+ # these are close regardless of tolerance -- i.e. they are equal
1694
+ self .assertIsClose (INF , INF )
1695
+ self .assertIsClose (INF , INF , abs_tol = 0.0 )
1696
+ self .assertIsClose (NINF , NINF )
1697
+ self .assertIsClose (NINF , NINF , abs_tol = 0.0 )
1698
+
1699
+ def test_inf_ninf_nan (self ):
1700
+ # these should never be close (following IEEE 754 rules for equality)
1701
+ not_close_examples = [(NAN , NAN ),
1702
+ (NAN , 1e-100 ),
1703
+ (1e-100 , NAN ),
1704
+ (INF , NAN ),
1705
+ (NAN , INF ),
1706
+ (INF , NINF ),
1707
+ (INF , 1.0 ),
1708
+ (1.0 , INF ),
1709
+ (INF , 1e308 ),
1710
+ (1e308 , INF )]
1711
+ # use largest reasonable tolerance
1712
+ self .assertAllNotClose (not_close_examples , abs_tol = 0.999999999999999 )
1713
+
1714
+ def test_zero_tolerance (self ):
1715
+ # test with zero tolerance
1716
+ zero_tolerance_close_examples = [(1.0 , 1.0 ),
1717
+ (- 3.4 , - 3.4 ),
1718
+ (- 1e-300 , - 1e-300 )]
1719
+ self .assertAllClose (zero_tolerance_close_examples , rel_tol = 0.0 )
1720
+
1721
+ zero_tolerance_not_close_examples = [(1.0 , 1.000000000000001 ),
1722
+ (0.99999999999999 , 1.0 ),
1723
+ (1.0e200 , .999999999999999e200 )]
1724
+ self .assertAllNotClose (zero_tolerance_not_close_examples , rel_tol = 0.0 )
1725
+
1726
+ def test_asymmetry (self ):
1727
+ # test the asymmetry example from PEP 485
1728
+ self .assertAllClose ([(9 , 10 ), (10 , 9 )], rel_tol = 0.1 )
1729
+
1730
+ def test_integers (self ):
1731
+ # test with integer values
1732
+ integer_examples = [(100000001 , 100000000 ),
1733
+ (123456789 , 123456788 )]
1734
+
1735
+ self .assertAllClose (integer_examples , rel_tol = 1e-8 )
1736
+ self .assertAllNotClose (integer_examples , rel_tol = 1e-9 )
1737
+
1738
+ # TODO the test is commented out due to GR-10712
1739
+ '''
1740
+ def test_decimals(self):
1741
+ # test with Decimal values
1742
+ from decimal import Decimal#
1743
+
1744
+ decimal_examples = [(Decimal('1.00000001'), Decimal('1.0')),
1745
+ (Decimal('1.00000001e-20'), Decimal('1.0e-20')),
1746
+ (Decimal('1.00000001e-100'), Decimal('1.0e-100')),
1747
+ (Decimal('1.00000001e20'), Decimal('1.0e20'))]
1748
+ self.assertAllClose(decimal_examples, rel_tol=1e-8)
1749
+ self.assertAllNotClose(decimal_examples, rel_tol=1e-9)
1750
+ '''
1751
+
1752
+ # TODO the test is commented out due to GR-10711
1753
+ '''
1754
+ def test_fractions(self):
1755
+ # test with Fraction values
1756
+ from fractions import Fraction
1757
+
1758
+ fraction_examples = [
1759
+ (Fraction(1, 100000000) + 1, Fraction(1)),
1760
+ (Fraction(100000001), Fraction(100000000)),
1761
+ (Fraction(10**8 + 1, 10**28), Fraction(1, 10**20))]
1762
+ self.assertAllClose(fraction_examples, rel_tol=1e-8)
1763
+ self.assertAllNotClose(fraction_examples, rel_tol=1e-9)
1764
+ '''
1765
+ def test_objects (self ):
1766
+ # these are close regardless of tolerance -- i.e. they are equal
1767
+ self .assertIsClose (MyFloat (), MyFloat ())
1768
+ self .assertIsClose (MyFloat (), MyFloat (), abs_tol = 0.0 )
1769
+ self .assertIsClose (MyFloat (), MyFloat (), abs_tol = MyFloat ())
1770
+ self .assertIsClose (MyFloat (), MyFloat (), rel_tol = 0.0 )
1771
+ self .assertIsClose (MyFloat (), MyFloat (), rel_tol = MyFloat ())
1772
+
1773
+ self .assertIsNotClose (MyFloat (), 10 )
0 commit comments