diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-04-20 21:13:33 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-04-20 21:13:33 (GMT) |
commit | 6736cf8d20b67b74e8e959622132963285156242 (patch) | |
tree | 6527638e42304a987b3ebc1541e4b75a3a838500 /Lib | |
parent | cccfc825e49760d8e46db38df50fb992a184b3ee (diff) | |
download | cpython-6736cf8d20b67b74e8e959622132963285156242.zip cpython-6736cf8d20b67b74e8e959622132963285156242.tar.gz cpython-6736cf8d20b67b74e8e959622132963285156242.tar.bz2 |
Issue #3166: Make long -> float (and int -> float) conversions
correctly rounded, using round-half-to-even. This ensures that the
value of float(n) doesn't depend on whether we're using 15-bit digits
or 30-bit digits for Python longs.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_int.py | 34 | ||||
-rw-r--r-- | Lib/test/test_long.py | 59 |
2 files changed, 93 insertions, 0 deletions
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index ce18ad2..514a98e 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -275,6 +275,40 @@ class IntTestCases(unittest.TestCase): self.assertEqual((a+1).bit_length(), i+1) self.assertEqual((-a-1).bit_length(), i+1) + @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), + "test requires IEEE 754 doubles") + def test_float_conversion(self): + # values exactly representable as floats + exact_values = [-2, -1, 0, 1, 2, 2**52, 2**53-1, 2**53, 2**53+2, + 2**53+4, 2**54-4, 2**54-2, 2**63, -2**63, 2**64, + -2**64, 10**20, 10**21, 10**22] + for value in exact_values: + self.assertEqual(int(float(int(value))), value) + + # test round-half-to-even + self.assertEqual(int(float(2**53+1)), 2**53) + self.assertEqual(int(float(2**53+2)), 2**53+2) + self.assertEqual(int(float(2**53+3)), 2**53+4) + self.assertEqual(int(float(2**53+5)), 2**53+4) + self.assertEqual(int(float(2**53+6)), 2**53+6) + self.assertEqual(int(float(2**53+7)), 2**53+8) + + self.assertEqual(int(float(-2**53-1)), -2**53) + self.assertEqual(int(float(-2**53-2)), -2**53-2) + self.assertEqual(int(float(-2**53-3)), -2**53-4) + self.assertEqual(int(float(-2**53-5)), -2**53-4) + self.assertEqual(int(float(-2**53-6)), -2**53-6) + self.assertEqual(int(float(-2**53-7)), -2**53-8) + + self.assertEqual(int(float(2**54-2)), 2**54-2) + self.assertEqual(int(float(2**54-1)), 2**54) + self.assertEqual(int(float(2**54+2)), 2**54) + self.assertEqual(int(float(2**54+3)), 2**54+4) + self.assertEqual(int(float(2**54+5)), 2**54+4) + self.assertEqual(int(float(2**54+6)), 2**54+8) + self.assertEqual(int(float(2**54+10)), 2**54+8) + self.assertEqual(int(float(2**54+11)), 2**54+12) + def test_intconversion(self): # Test __int__() class ClassicMissingMethods: diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 1a0e33d..b41d270 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -645,6 +645,65 @@ class LongTest(unittest.TestCase): else: self.assertRaises(TypeError, pow,longx, longy, long(z)) + @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), + "test requires IEEE 754 doubles") + def test_float_conversion(self): + import sys + DBL_MAX = sys.float_info.max + DBL_MAX_EXP = sys.float_info.max_exp + DBL_MANT_DIG = sys.float_info.mant_dig + + exact_values = [0L, 1L, 2L, + long(2**53-3), + long(2**53-2), + long(2**53-1), + long(2**53), + long(2**53+2), + long(2**54-4), + long(2**54-2), + long(2**54), + long(2**54+4)] + for x in exact_values: + self.assertEqual(long(float(x)), x) + self.assertEqual(long(float(-x)), -x) + + # test round-half-even + for x, y in [(1, 0), (2, 2), (3, 4), (4, 4), (5, 4), (6, 6), (7, 8)]: + for p in xrange(15): + self.assertEqual(long(float(2L**p*(2**53+x))), 2L**p*(2**53+y)) + + for x, y in [(0, 0), (1, 0), (2, 0), (3, 4), (4, 4), (5, 4), (6, 8), + (7, 8), (8, 8), (9, 8), (10, 8), (11, 12), (12, 12), + (13, 12), (14, 16), (15, 16)]: + for p in xrange(15): + self.assertEqual(long(float(2L**p*(2**54+x))), 2L**p*(2**54+y)) + + # behaviour near extremes of floating-point range + long_dbl_max = long(DBL_MAX) + top_power = 2**DBL_MAX_EXP + halfway = (long_dbl_max + top_power)/2 + self.assertEqual(float(long_dbl_max), DBL_MAX) + self.assertEqual(float(long_dbl_max+1), DBL_MAX) + self.assertEqual(float(halfway-1), DBL_MAX) + self.assertRaises(OverflowError, float, halfway) + self.assertEqual(float(1-halfway), -DBL_MAX) + self.assertRaises(OverflowError, float, -halfway) + self.assertRaises(OverflowError, float, top_power-1) + self.assertRaises(OverflowError, float, top_power) + self.assertRaises(OverflowError, float, top_power+1) + self.assertRaises(OverflowError, float, 2*top_power-1) + self.assertRaises(OverflowError, float, 2*top_power) + self.assertRaises(OverflowError, float, top_power*top_power) + + for p in xrange(100): + x = long(2**p * (2**53 + 1) + 1) + y = long(2**p * (2**53+ 2)) + self.assertEqual(long(float(x)), y) + + x = long(2**p * (2**53 + 1)) + y = long(2**p * 2**53) + self.assertEqual(long(float(x)), y) + def test_float_overflow(self): import math |