Skip to content

Commit 6949180

Browse files
authored
Merge pull request #3448 from YYun-D/test_math_modify
Update test_math.py to cpython 3.10
2 parents 7b79c09 + 3070b19 commit 6949180

File tree

1 file changed

+93
-27
lines changed

1 file changed

+93
-27
lines changed

Lib/test/test_math.py

Lines changed: 93 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Python test set -- math module
32
# XXXX Should not do tests around zero only
43

@@ -19,7 +18,6 @@
1918
NAN = float('nan')
2019
INF = float('inf')
2120
NINF = float('-inf')
22-
2321
FLOAT_MAX = sys.float_info.max
2422
FLOAT_MIN = sys.float_info.min
2523

@@ -43,8 +41,10 @@ def to_ulps(x):
4341
adjacent floats are converted to adjacent integers. Then
4442
abs(ulps(x) - ulps(y)) gives the difference in ulps between two
4543
floats.
44+
4645
The results from this function will only make sense on platforms
4746
where native doubles are represented in IEEE 754 binary64 format.
47+
4848
Note: 0.0 and -0.0 are converted to 0 and -1, respectively.
4949
"""
5050
n = struct.unpack('<q', struct.pack('<d', x))[0]
@@ -81,6 +81,7 @@ def count_set_bits(n):
8181
def partial_product(start, stop):
8282
"""Product of integers in range(start, stop, 2), computed recursively.
8383
start and stop should both be odd, with start <= stop.
84+
8485
"""
8586
numfactors = (stop - start) >> 1
8687
if not numfactors:
@@ -94,6 +95,7 @@ def partial_product(start, stop):
9495
def py_factorial(n):
9596
"""Factorial of nonnegative integer n, via "Binary Split Factorial Formula"
9697
described at http://www.luschny.de/math/factorial/binarysplitfact.html
98+
9799
"""
98100
inner = outer = 1
99101
for i in reversed(range(n.bit_length())):
@@ -105,6 +107,7 @@ def ulp_abs_check(expected, got, ulp_tol, abs_tol):
105107
"""Given finite floats `expected` and `got`, check that they're
106108
approximately equal to within the given number of ulps or the
107109
given absolute tolerance, whichever is bigger.
110+
108111
Returns None on success and an error message on failure.
109112
"""
110113
ulp_error = abs(to_ulps(expected) - to_ulps(got))
@@ -120,12 +123,14 @@ def ulp_abs_check(expected, got, ulp_tol, abs_tol):
120123

121124
def parse_mtestfile(fname):
122125
"""Parse a file with test values
126+
123127
-- starts a comment
124128
blank lines, or lines containing only a comment, are ignored
125129
other lines are expected to have the form
126130
id fn arg -> expected [flag]*
131+
127132
"""
128-
with open(fname) as fp:
133+
with open(fname, encoding="utf-8") as fp:
129134
for line in fp:
130135
# strip comments, and skip blank lines
131136
if '--' in line:
@@ -144,10 +149,11 @@ def parse_mtestfile(fname):
144149

145150
def parse_testfile(fname):
146151
"""Parse a file with test values
152+
147153
Empty lines or lines starting with -- are ignored
148154
yields id, fn, arg_real, arg_imag, exp_real, exp_imag
149155
"""
150-
with open(fname) as fp:
156+
with open(fname, encoding="utf-8") as fp:
151157
for line in fp:
152158
# skip comment lines and blank lines
153159
if line.startswith('--') or not line.strip():
@@ -170,9 +176,11 @@ def result_check(expected, got, ulp_tol=5, abs_tol=0.0):
170176
"""Compare arguments expected and got, as floats, if either
171177
is a float, using a tolerance expressed in multiples of
172178
ulp(expected) or absolutely (if given and greater).
179+
173180
As a convenience, when neither argument is a float, and for
174181
non-finite floats, exact equality is demanded. Also, nan==nan
175182
as far as this function is concerned.
183+
176184
Returns None on success and an error message on failure.
177185
"""
178186

@@ -232,6 +240,7 @@ def ftest(self, name, got, expected, ulp_tol=5, abs_tol=0.0):
232240
"""Compare arguments expected and got, as floats, if either
233241
is a float, using a tolerance expressed in multiples of
234242
ulp(expected) or absolutely, whichever is greater.
243+
235244
As a convenience, when neither argument is a float, and for
236245
non-finite floats, exact equality is demanded. Also, nan==nan
237246
in this function.
@@ -492,17 +501,11 @@ def testFactorial(self):
492501
self.assertRaises(ValueError, math.factorial, -1)
493502
self.assertRaises(ValueError, math.factorial, -10**100)
494503

495-
# TODO: RUSTPYTHON
496-
@unittest.expectedFailure
497504
def testFactorialNonIntegers(self):
498-
with self.assertWarns(DeprecationWarning):
499-
self.assertEqual(math.factorial(5.0), 120)
500-
with self.assertWarns(DeprecationWarning):
501-
self.assertRaises(ValueError, math.factorial, 5.2)
502-
with self.assertWarns(DeprecationWarning):
503-
self.assertRaises(ValueError, math.factorial, -1.0)
504-
with self.assertWarns(DeprecationWarning):
505-
self.assertRaises(ValueError, math.factorial, -1e100)
505+
self.assertRaises(TypeError, math.factorial, 5.0)
506+
self.assertRaises(TypeError, math.factorial, 5.2)
507+
self.assertRaises(TypeError, math.factorial, -1.0)
508+
self.assertRaises(TypeError, math.factorial, -1e100)
506509
self.assertRaises(TypeError, math.factorial, decimal.Decimal('5'))
507510
self.assertRaises(TypeError, math.factorial, decimal.Decimal('5.2'))
508511
self.assertRaises(TypeError, math.factorial, "5")
@@ -513,8 +516,7 @@ def testFactorialHugeInputs(self):
513516
# Currently raises OverflowError for inputs that are too large
514517
# to fit into a C long.
515518
self.assertRaises(OverflowError, math.factorial, 10**100)
516-
with self.assertWarns(DeprecationWarning):
517-
self.assertRaises(OverflowError, math.factorial, 1e100)
519+
self.assertRaises(TypeError, math.factorial, 1e100)
518520

519521
def testFloor(self):
520522
self.assertRaises(TypeError, math.floor)
@@ -587,7 +589,6 @@ def testfrexp(name, result, expected):
587589
self.assertEqual(math.frexp(NINF)[0], NINF)
588590
self.assertTrue(math.isnan(math.frexp(NAN)[0]))
589591

590-
591592
@requires_IEEE_754
592593
@unittest.skipIf(HAVE_DOUBLE_ROUNDING,
593594
"fsum is not exact on machines with double rounding")
@@ -611,6 +612,7 @@ def msum(iterable):
611612
"""Full precision summation. Compute sum(iterable) without any
612613
intermediate accumulation of error. Based on the 'lsum' function
613614
at http://code.activestate.com/recipes/393090/
615+
614616
"""
615617
tmant, texp = 0, 0
616618
for x in iterable:
@@ -684,8 +686,6 @@ def msum(iterable):
684686
s = msum(vals)
685687
self.assertEqual(msum(vals), math.fsum(vals))
686688

687-
688-
# Python 3.9
689689
def testGcd(self):
690690
gcd = math.gcd
691691
self.assertEqual(gcd(0, 0), 0)
@@ -726,7 +726,7 @@ def testGcd(self):
726726
self.assertRaises(TypeError, gcd, 120.0, 84)
727727
self.assertRaises(TypeError, gcd, 120, 84.0)
728728
self.assertRaises(TypeError, gcd, 120, 1, 84.0)
729-
#self.assertEqual(gcd(MyIndexable(120), MyIndexable(84)), 12) # TODO: RUSTPYTHON
729+
self.assertEqual(gcd(MyIndexable(120), MyIndexable(84)), 12)
730730

731731
def testHypot(self):
732732
from decimal import Decimal
@@ -795,13 +795,79 @@ def testHypot(self):
795795
# Verify scaling for extremely large values
796796
fourthmax = FLOAT_MAX / 4.0
797797
for n in range(32):
798-
self.assertEqual(hypot(*([fourthmax]*n)), fourthmax * math.sqrt(n))
798+
self.assertTrue(math.isclose(hypot(*([fourthmax]*n)),
799+
fourthmax * math.sqrt(n)))
799800

800801
# Verify scaling for extremely small values
801802
for exp in range(32):
802803
scale = FLOAT_MIN / 2.0 ** exp
803804
self.assertEqual(math.hypot(4*scale, 3*scale), 5*scale)
804805

806+
@requires_IEEE_754
807+
@unittest.skipIf(HAVE_DOUBLE_ROUNDING,
808+
"hypot() loses accuracy on machines with double rounding")
809+
# TODO: RUSTPYTHON
810+
@unittest.expectedFailure
811+
def testHypotAccuracy(self):
812+
# Verify improved accuracy in cases that were known to be inaccurate.
813+
#
814+
# The new algorithm's accuracy depends on IEEE 754 arithmetic
815+
# guarantees, on having the usual ROUND HALF EVEN rounding mode, on
816+
# the system not having double rounding due to extended precision,
817+
# and on the compiler maintaining the specified order of operations.
818+
#
819+
# This test is known to succeed on most of our builds. If it fails
820+
# some build, we either need to add another skipIf if the cause is
821+
# identifiable; otherwise, we can remove this test entirely.
822+
823+
hypot = math.hypot
824+
Decimal = decimal.Decimal
825+
high_precision = decimal.Context(prec=500)
826+
827+
for hx, hy in [
828+
# Cases with a 1 ulp error in Python 3.7 compiled with Clang
829+
('0x1.10e89518dca48p+29', '0x1.1970f7565b7efp+30'),
830+
('0x1.10106eb4b44a2p+29', '0x1.ef0596cdc97f8p+29'),
831+
('0x1.459c058e20bb7p+30', '0x1.993ca009b9178p+29'),
832+
('0x1.378371ae67c0cp+30', '0x1.fbe6619854b4cp+29'),
833+
('0x1.f4cd0574fb97ap+29', '0x1.50fe31669340ep+30'),
834+
('0x1.494b2cdd3d446p+29', '0x1.212a5367b4c7cp+29'),
835+
('0x1.f84e649f1e46dp+29', '0x1.1fa56bef8eec4p+30'),
836+
('0x1.2e817edd3d6fap+30', '0x1.eb0814f1e9602p+29'),
837+
('0x1.0d3a6e3d04245p+29', '0x1.32a62fea52352p+30'),
838+
('0x1.888e19611bfc5p+29', '0x1.52b8e70b24353p+29'),
839+
840+
# Cases with 2 ulp error in Python 3.8
841+
('0x1.538816d48a13fp+29', '0x1.7967c5ca43e16p+29'),
842+
('0x1.57b47b7234530p+29', '0x1.74e2c7040e772p+29'),
843+
('0x1.821b685e9b168p+30', '0x1.677dc1c1e3dc6p+29'),
844+
('0x1.9e8247f67097bp+29', '0x1.24bd2dc4f4baep+29'),
845+
('0x1.b73b59e0cb5f9p+29', '0x1.da899ab784a97p+28'),
846+
('0x1.94a8d2842a7cfp+30', '0x1.326a51d4d8d8ap+30'),
847+
('0x1.e930b9cd99035p+29', '0x1.5a1030e18dff9p+30'),
848+
('0x1.1592bbb0e4690p+29', '0x1.a9c337b33fb9ap+29'),
849+
('0x1.1243a50751fd4p+29', '0x1.a5a10175622d9p+29'),
850+
('0x1.57a8596e74722p+30', '0x1.42d1af9d04da9p+30'),
851+
852+
# Cases with 1 ulp error in version fff3c28052e6b0
853+
('0x1.ee7dbd9565899p+29', '0x1.7ab4d6fc6e4b4p+29'),
854+
('0x1.5c6bfbec5c4dcp+30', '0x1.02511184b4970p+30'),
855+
('0x1.59dcebba995cap+30', '0x1.50ca7e7c38854p+29'),
856+
('0x1.768cdd94cf5aap+29', '0x1.9cfdc5571d38ep+29'),
857+
('0x1.dcf137d60262ep+29', '0x1.1101621990b3ep+30'),
858+
('0x1.3a2d006e288b0p+30', '0x1.e9a240914326cp+29'),
859+
('0x1.62a32f7f53c61p+29', '0x1.47eb6cd72684fp+29'),
860+
('0x1.d3bcb60748ef2p+29', '0x1.3f13c4056312cp+30'),
861+
('0x1.282bdb82f17f3p+30', '0x1.640ba4c4eed3ap+30'),
862+
('0x1.89d8c423ea0c6p+29', '0x1.d35dcfe902bc3p+29'),
863+
]:
864+
x = float.fromhex(hx)
865+
y = float.fromhex(hy)
866+
with self.subTest(hx=hx, hy=hy, x=x, y=y):
867+
with decimal.localcontext(high_precision):
868+
z = float((Decimal(x)**2 + Decimal(y)**2).sqrt())
869+
self.assertEqual(hypot(x, y), z)
870+
805871
def testDist(self):
806872
from decimal import Decimal as D
807873
from fractions import Fraction as F
@@ -904,8 +970,8 @@ class T(tuple):
904970
for n in range(32):
905971
p = (fourthmax,) * n
906972
q = (0.0,) * n
907-
self.assertEqual(dist(p, q), fourthmax * math.sqrt(n))
908-
self.assertEqual(dist(q, p), fourthmax * math.sqrt(n))
973+
self.assertTrue(math.isclose(dist(p, q), fourthmax * math.sqrt(n)))
974+
self.assertTrue(math.isclose(dist(q, p), fourthmax * math.sqrt(n)))
909975

910976
# Verify scaling for extremely small values
911977
for exp in range(32):
@@ -968,8 +1034,7 @@ def __index__(self):
9681034
with self.assertRaises(TypeError):
9691035
math.isqrt(value)
9701036

971-
# Python 3.9
972-
def testlcm(self):
1037+
def test_lcm(self):
9731038
lcm = math.lcm
9741039
self.assertEqual(lcm(0, 0), 0)
9751040
self.assertEqual(lcm(1, 0), 0)
@@ -1011,7 +1076,7 @@ def testlcm(self):
10111076
self.assertRaises(TypeError, lcm, 120.0, 84)
10121077
self.assertRaises(TypeError, lcm, 120, 84.0)
10131078
self.assertRaises(TypeError, lcm, 120, 0, 84.0)
1014-
# self.assertEqual(lcm(MyIndexable(120), MyIndexable(84)), 840) # TODO: RUSTPYTHON
1079+
self.assertEqual(lcm(MyIndexable(120), MyIndexable(84)), 840)
10151080

10161081
def testLdexp(self):
10171082
self.assertRaises(TypeError, math.ldexp)
@@ -1987,7 +2052,7 @@ def test_ulp(self):
19872052

19882053
# min and max
19892054
self.assertEqual(math.ulp(0.0),
1990-
sys.float_info.min * sys.float_info.epsilon)
2055+
sys.float_info.min * sys.float_info.epsilon)
19912056
self.assertEqual(math.ulp(FLOAT_MAX),
19922057
FLOAT_MAX - math.nextafter(FLOAT_MAX, -INF))
19932058

@@ -2024,6 +2089,7 @@ def assertIsNaN(self, value):
20242089

20252090
def assertEqualSign(self, x, y):
20262091
"""Similar to assertEqual(), but compare also the sign with copysign().
2092+
20272093
Function useful to compare signed zeros.
20282094
"""
20292095
self.assertEqual(x, y)

0 commit comments

Comments
 (0)