diff options
author | Victor Stinner <vstinner@python.org> | 2020-01-13 11:44:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-13 11:44:35 (GMT) |
commit | 0b2ab21956fbab8eab6d064060d4544499730316 (patch) | |
tree | cb0be30aef9fcb0cba4aee16049219d908afdc23 /Lib/test | |
parent | 7ba6f18de2582755ae31888ba6a4237d96dddc48 (diff) | |
download | cpython-0b2ab21956fbab8eab6d064060d4544499730316.zip cpython-0b2ab21956fbab8eab6d064060d4544499730316.tar.gz cpython-0b2ab21956fbab8eab6d064060d4544499730316.tar.bz2 |
bpo-39310: Add math.ulp(x) (GH-17965)
Add math.ulp(): return the value of the least significant bit
of a float.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_math.py | 55 |
1 files changed, 27 insertions, 28 deletions
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index b64fd41..6d10227 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -53,30 +53,6 @@ def to_ulps(x): return n -def ulp(x): - """Return the value of the least significant bit of a - float x, such that the first float bigger than x is x+ulp(x). - Then, given an expected result x and a tolerance of n ulps, - the result y should be such that abs(y-x) <= n * ulp(x). - The results from this function will only make sense on platforms - where native doubles are represented in IEEE 754 binary64 format. - """ - x = abs(float(x)) - if math.isnan(x) or math.isinf(x): - return x - - # Find next float up from x. - n = struct.unpack('<q', struct.pack('<d', x))[0] - x_next = struct.unpack('<d', struct.pack('<q', n + 1))[0] - if math.isinf(x_next): - # Corner case: x was the largest finite float. Then it's - # not an exact power of two, so we can take the difference - # between x and the previous float. - x_prev = struct.unpack('<d', struct.pack('<q', n - 1))[0] - return x - x_prev - else: - return x_next - x - # Here's a pure Python version of the math.factorial algorithm, for # documentation and comparison purposes. # @@ -470,9 +446,9 @@ class MathTests(unittest.TestCase): def testCos(self): self.assertRaises(TypeError, math.cos) - self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0, abs_tol=ulp(1)) + self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0, abs_tol=math.ulp(1)) self.ftest('cos(0)', math.cos(0), 1) - self.ftest('cos(pi/2)', math.cos(math.pi/2), 0, abs_tol=ulp(1)) + self.ftest('cos(pi/2)', math.cos(math.pi/2), 0, abs_tol=math.ulp(1)) self.ftest('cos(pi)', math.cos(math.pi), -1) try: self.assertTrue(math.isnan(math.cos(INF))) @@ -1445,7 +1421,7 @@ class MathTests(unittest.TestCase): self.assertRaises(TypeError, math.tanh) self.ftest('tanh(0)', math.tanh(0), 0) self.ftest('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0, - abs_tol=ulp(1)) + abs_tol=math.ulp(1)) self.ftest('tanh(inf)', math.tanh(INF), 1) self.ftest('tanh(-inf)', math.tanh(NINF), -1) self.assertTrue(math.isnan(math.tanh(NAN))) @@ -2036,7 +2012,7 @@ class IsCloseTests(unittest.TestCase): def assertEqualSign(self, x, y): """Similar to assertEqual(), but compare also the sign. - Function useful to check to signed zero. + Function useful to compare signed zeros. """ self.assertEqual(x, y) self.assertEqual(math.copysign(1.0, x), math.copysign(1.0, y)) @@ -2087,6 +2063,29 @@ class IsCloseTests(unittest.TestCase): 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)) + def test_main(): from doctest import DocFileSuite |