Issue #1811: Improve accuracy and consistency of true division for integers.
[python.git] / Lib / test / test_long_future.py
blob25462bfc30a46ae2bf181bf366a98d2748e2f710
1 from __future__ import division
2 # When true division is the default, get rid of this and add it to
3 # test_long.py instead. In the meantime, it's too obscure to try to
4 # trick just part of test_long into using future division.
6 import sys
7 import random
8 import unittest
9 from test.test_support import run_unittest
11 # decorator for skipping tests on non-IEEE 754 platforms
12 requires_IEEE_754 = unittest.skipUnless(
13 float.__getformat__("double").startswith("IEEE"),
14 "test requires IEEE 754 doubles")
16 DBL_MAX = sys.float_info.max
17 DBL_MAX_EXP = sys.float_info.max_exp
18 DBL_MIN_EXP = sys.float_info.min_exp
19 DBL_MANT_DIG = sys.float_info.mant_dig
20 DBL_MIN_OVERFLOW = 2**DBL_MAX_EXP - 2**(DBL_MAX_EXP - DBL_MANT_DIG - 1)
22 # pure Python version of correctly-rounded true division
23 def truediv(a, b):
24 """Correctly-rounded true division for integers."""
25 negative = a^b < 0
26 a, b = abs(a), abs(b)
28 # exceptions: division by zero, overflow
29 if not b:
30 raise ZeroDivisionError("division by zero")
31 if a >= DBL_MIN_OVERFLOW * b:
32 raise OverflowError("int/int too large to represent as a float")
34 # find integer d satisfying 2**(d - 1) <= a/b < 2**d
35 d = a.bit_length() - b.bit_length()
36 if d >= 0 and a >= 2**d * b or d < 0 and a * 2**-d >= b:
37 d += 1
39 # compute 2**-exp * a / b for suitable exp
40 exp = max(d, DBL_MIN_EXP) - DBL_MANT_DIG
41 a, b = a << max(-exp, 0), b << max(exp, 0)
42 q, r = divmod(a, b)
44 # round-half-to-even: fractional part is r/b, which is > 0.5 iff
45 # 2*r > b, and == 0.5 iff 2*r == b.
46 if 2*r > b or 2*r == b and q % 2 == 1:
47 q += 1
49 result = float(q) * 2.**exp
50 return -result if negative else result
52 class TrueDivisionTests(unittest.TestCase):
53 def test(self):
54 huge = 1L << 40000
55 mhuge = -huge
56 self.assertEqual(huge / huge, 1.0)
57 self.assertEqual(mhuge / mhuge, 1.0)
58 self.assertEqual(huge / mhuge, -1.0)
59 self.assertEqual(mhuge / huge, -1.0)
60 self.assertEqual(1 / huge, 0.0)
61 self.assertEqual(1L / huge, 0.0)
62 self.assertEqual(1 / mhuge, 0.0)
63 self.assertEqual(1L / mhuge, 0.0)
64 self.assertEqual((666 * huge + (huge >> 1)) / huge, 666.5)
65 self.assertEqual((666 * mhuge + (mhuge >> 1)) / mhuge, 666.5)
66 self.assertEqual((666 * huge + (huge >> 1)) / mhuge, -666.5)
67 self.assertEqual((666 * mhuge + (mhuge >> 1)) / huge, -666.5)
68 self.assertEqual(huge / (huge << 1), 0.5)
69 self.assertEqual((1000000 * huge) / huge, 1000000)
71 namespace = {'huge': huge, 'mhuge': mhuge}
73 for overflow in ["float(huge)", "float(mhuge)",
74 "huge / 1", "huge / 2L", "huge / -1", "huge / -2L",
75 "mhuge / 100", "mhuge / 100L"]:
76 # If the "eval" does not happen in this module,
77 # true division is not enabled
78 with self.assertRaises(OverflowError):
79 eval(overflow, namespace)
81 for underflow in ["1 / huge", "2L / huge", "-1 / huge", "-2L / huge",
82 "100 / mhuge", "100L / mhuge"]:
83 result = eval(underflow, namespace)
84 self.assertEqual(result, 0.0, 'expected underflow to 0 '
85 'from {!r}'.format(underflow))
87 for zero in ["huge / 0", "huge / 0L", "mhuge / 0", "mhuge / 0L"]:
88 with self.assertRaises(ZeroDivisionError):
89 eval(zero, namespace)
91 def check_truediv(self, a, b, skip_small=True):
92 """Verify that the result of a/b is correctly rounded, by
93 comparing it with a pure Python implementation of correctly
94 rounded division. b should be nonzero."""
96 a, b = long(a), long(b)
98 # skip check for small a and b: in this case, the current
99 # implementation converts the arguments to float directly and
100 # then applies a float division. This can give doubly-rounded
101 # results on x87-using machines (particularly 32-bit Linux).
102 if skip_small and max(abs(a), abs(b)) < 2**DBL_MANT_DIG:
103 return
105 try:
106 # use repr so that we can distinguish between -0.0 and 0.0
107 expected = repr(truediv(a, b))
108 except OverflowError:
109 expected = 'overflow'
110 except ZeroDivisionError:
111 expected = 'zerodivision'
113 try:
114 got = repr(a / b)
115 except OverflowError:
116 got = 'overflow'
117 except ZeroDivisionError:
118 got = 'zerodivision'
120 if expected != got:
121 self.fail("Incorrectly rounded division {}/{}: expected {!r}, "
122 "got {!r}.".format(a, b, expected, got))
124 @requires_IEEE_754
125 def test_correctly_rounded_true_division(self):
126 # more stringent tests than those above, checking that the
127 # result of true division of ints is always correctly rounded.
128 # This test should probably be considered CPython-specific.
130 # Exercise all the code paths not involving Gb-sized ints.
131 # ... divisions involving zero
132 self.check_truediv(123, 0)
133 self.check_truediv(-456, 0)
134 self.check_truediv(0, 3)
135 self.check_truediv(0, -3)
136 self.check_truediv(0, 0)
137 # ... overflow or underflow by large margin
138 self.check_truediv(671 * 12345 * 2**DBL_MAX_EXP, 12345)
139 self.check_truediv(12345, 345678 * 2**(DBL_MANT_DIG - DBL_MIN_EXP))
140 # ... a much larger or smaller than b
141 self.check_truediv(12345*2**100, 98765)
142 self.check_truediv(12345*2**30, 98765*7**81)
143 # ... a / b near a boundary: one of 1, 2**DBL_MANT_DIG, 2**DBL_MIN_EXP,
144 # 2**DBL_MAX_EXP, 2**(DBL_MIN_EXP-DBL_MANT_DIG)
145 bases = (0, DBL_MANT_DIG, DBL_MIN_EXP,
146 DBL_MAX_EXP, DBL_MIN_EXP - DBL_MANT_DIG)
147 for base in bases:
148 for exp in range(base - 15, base + 15):
149 self.check_truediv(75312*2**max(exp, 0), 69187*2**max(-exp, 0))
150 self.check_truediv(69187*2**max(exp, 0), 75312*2**max(-exp, 0))
152 # overflow corner case
153 for m in [1, 2, 7, 17, 12345, 7**100,
154 -1, -2, -5, -23, -67891, -41**50]:
155 for n in range(-10, 10):
156 self.check_truediv(m*DBL_MIN_OVERFLOW + n, m)
157 self.check_truediv(m*DBL_MIN_OVERFLOW + n, -m)
159 # check detection of inexactness in shifting stage
160 for n in range(250):
161 # (2**DBL_MANT_DIG+1)/(2**DBL_MANT_DIG) lies halfway
162 # between two representable floats, and would usually be
163 # rounded down under round-half-to-even. The tiniest of
164 # additions to the numerator should cause it to be rounded
165 # up instead.
166 self.check_truediv((2**DBL_MANT_DIG + 1)*12345*2**200 + 2**n,
167 2**DBL_MANT_DIG*12345)
169 # 1/2731 is one of the smallest division cases that's subject
170 # to double rounding on IEEE 754 machines working internally with
171 # 64-bit precision. On such machines, the next check would fail,
172 # were it not explicitly skipped in check_truediv.
173 self.check_truediv(1, 2731)
175 # a particularly bad case for the old algorithm: gives an
176 # error of close to 3.5 ulps.
177 self.check_truediv(295147931372582273023, 295147932265116303360)
178 for i in range(1000):
179 self.check_truediv(10**(i+1), 10**i)
180 self.check_truediv(10**i, 10**(i+1))
182 # test round-half-to-even behaviour, normal result
183 for m in [1, 2, 4, 7, 8, 16, 17, 32, 12345, 7**100,
184 -1, -2, -5, -23, -67891, -41**50]:
185 for n in range(-10, 10):
186 self.check_truediv(2**DBL_MANT_DIG*m + n, m)
188 # test round-half-to-even, subnormal result
189 for n in range(-20, 20):
190 self.check_truediv(n, 2**1076)
192 # largeish random divisions: a/b where |a| <= |b| <=
193 # 2*|a|; |ans| is between 0.5 and 1.0, so error should
194 # always be bounded by 2**-54 with equality possible only
195 # if the least significant bit of q=ans*2**53 is zero.
196 for M in [10**10, 10**100, 10**1000]:
197 for i in range(1000):
198 a = random.randrange(1, M)
199 b = random.randrange(a, 2*a+1)
200 self.check_truediv(a, b)
201 self.check_truediv(-a, b)
202 self.check_truediv(a, -b)
203 self.check_truediv(-a, -b)
205 # and some (genuinely) random tests
206 for _ in range(10000):
207 a_bits = random.randrange(1000)
208 b_bits = random.randrange(1, 1000)
209 x = random.randrange(2**a_bits)
210 y = random.randrange(1, 2**b_bits)
211 self.check_truediv(x, y)
212 self.check_truediv(x, -y)
213 self.check_truediv(-x, y)
214 self.check_truediv(-x, -y)
217 def test_main():
218 run_unittest(TrueDivisionTests)
220 if __name__ == "__main__":
221 test_main()