blob: 2b250df75f2e527dccf1b5e591406661c3cc833c [file] [log] [blame]
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001
2import unittest, struct
Christian Heimes827b35c2007-12-10 22:19:17 +00003import os
Eric Smith0923d1d2009-04-16 20:16:10 +00004import sys
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Christian Heimes53876d92008-04-19 00:31:39 +00006import math
Mark Dickinson65fe25e2008-07-16 11:30:51 +00007from math import isinf, isnan, copysign, ldexp
Christian Heimes53876d92008-04-19 00:31:39 +00008import operator
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +00009import random, fractions
Mark Dickinson46672512010-01-12 23:09:26 +000010import re
Michael W. Hudsonba283e22005-05-27 15:23:20 +000011
Christian Heimes53876d92008-04-19 00:31:39 +000012INF = float("inf")
13NAN = float("nan")
Christian Heimes99170a52007-12-19 02:07:34 +000014
Mark Dickinson33154382010-12-04 12:42:18 +000015have_getformat = hasattr(float, "__getformat__")
16requires_getformat = unittest.skipUnless(have_getformat,
17 "requires __getformat__")
18requires_setformat = unittest.skipUnless(hasattr(float, "__setformat__"),
19 "requires __setformat__")
20# decorator for skipping tests on non-IEEE 754 platforms
21requires_IEEE_754 = unittest.skipUnless(have_getformat and
22 float.__getformat__("double").startswith("IEEE"),
23 "test requires IEEE 754 doubles")
24
Eric Smith0923d1d2009-04-16 20:16:10 +000025#locate file with float format test values
26test_dir = os.path.dirname(__file__) or os.curdir
27format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
28
Mark Dickinson46672512010-01-12 23:09:26 +000029finite_decimal_parser = re.compile(r""" # A numeric string consists of:
30 (?P<sign>[-+])? # an optional sign, followed by
31 (?=\d|\.\d) # a number with at least one digit
32 (?P<int>\d*) # having a (possibly empty) integer part
33 (?:\.(?P<frac>\d*))? # followed by an optional fractional part
34 (?:E(?P<exp>[-+]?\d+))? # and an optional exponent
35 \Z
36""", re.VERBOSE | re.IGNORECASE | re.UNICODE).match
37
38# Pure Python version of correctly rounded string->float conversion.
39# Avoids any use of floating-point by returning the result as a hex string.
40def strtod(s, mant_dig=53, min_exp = -1021, max_exp = 1024):
41 """Convert a finite decimal string to a hex string representing an
42 IEEE 754 binary64 float. Return 'inf' or '-inf' on overflow.
43 This function makes no use of floating-point arithmetic at any
44 stage."""
45
46 # parse string into a pair of integers 'a' and 'b' such that
47 # abs(decimal value) = a/b, and a boolean 'negative'.
48 m = finite_decimal_parser(s)
49 if m is None:
50 raise ValueError('invalid numeric string')
51 fraction = m.group('frac') or ''
52 intpart = int(m.group('int') + fraction)
53 exp = int(m.group('exp') or '0') - len(fraction)
54 negative = m.group('sign') == '-'
55 a, b = intpart*10**max(exp, 0), 10**max(0, -exp)
56
57 # quick return for zeros
58 if not a:
59 return '-0x0.0p+0' if negative else '0x0.0p+0'
60
61 # compute exponent e for result; may be one too small in the case
62 # that the rounded value of a/b lies in a different binade from a/b
63 d = a.bit_length() - b.bit_length()
64 d += (a >> d if d >= 0 else a << -d) >= b
65 e = max(d, min_exp) - mant_dig
66
67 # approximate a/b by number of the form q * 2**e; adjust e if necessary
68 a, b = a << max(-e, 0), b << max(e, 0)
69 q, r = divmod(a, b)
70 if 2*r > b or 2*r == b and q & 1:
71 q += 1
72 if q.bit_length() == mant_dig+1:
73 q //= 2
74 e += 1
75
76 # double check that (q, e) has the right form
77 assert q.bit_length() <= mant_dig and e >= min_exp - mant_dig
78 assert q.bit_length() == mant_dig or e == min_exp - mant_dig
79
80 # check for overflow and underflow
81 if e + q.bit_length() > max_exp:
82 return '-inf' if negative else 'inf'
83 if not q:
84 return '-0x0.0p+0' if negative else '0x0.0p+0'
85
86 # for hex representation, shift so # bits after point is a multiple of 4
87 hexdigs = 1 + (mant_dig-2)//4
88 shift = 3 - (mant_dig-2)%4
89 q, e = q << shift, e - shift
90 return '{}0x{:x}.{:0{}x}p{:+d}'.format(
91 '-' if negative else '',
92 q // 16**hexdigs,
93 q % 16**hexdigs,
94 hexdigs,
95 e + 4*hexdigs)
96
Christian Heimes81ee3ef2008-05-04 22:42:01 +000097class GeneralFloatCases(unittest.TestCase):
98
99 def test_float(self):
100 self.assertEqual(float(3.14), 3.14)
101 self.assertEqual(float(314), 314.0)
102 self.assertEqual(float(" 3.14 "), 3.14)
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +0000103 self.assertEqual(float(b" 3.14 "), 3.14)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000104 self.assertRaises(ValueError, float, " 0x3.1 ")
105 self.assertRaises(ValueError, float, " -0x3.p-1 ")
106 self.assertRaises(ValueError, float, " +0x3.p-1 ")
107 self.assertRaises(ValueError, float, "++3.14")
108 self.assertRaises(ValueError, float, "+-3.14")
109 self.assertRaises(ValueError, float, "-+3.14")
110 self.assertRaises(ValueError, float, "--3.14")
Eric Smith0923d1d2009-04-16 20:16:10 +0000111 self.assertRaises(ValueError, float, ".nan")
112 self.assertRaises(ValueError, float, "+.inf")
113 self.assertRaises(ValueError, float, ".")
114 self.assertRaises(ValueError, float, "-.")
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +0000115 self.assertEqual(float(b" \u0663.\u0661\u0664 ".decode('raw-unicode-escape')), 3.14)
Mark Dickinsonee26c982009-10-27 22:13:18 +0000116 # extra long strings should not be a problem
117 float(b'.' + b'1'*1000)
118 float('.' + '1'*1000)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000119
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000120 @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000121 def test_float_with_comma(self):
122 # set locale to something that doesn't use '.' for the decimal point
123 # float must not accept the locale specific decimal point but
Ezio Melotti13925002011-03-16 11:05:33 +0200124 # it still has to accept the normal python syntax
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000125 import locale
126 if not locale.localeconv()['decimal_point'] == ',':
127 return
128
129 self.assertEqual(float(" 3.14 "), 3.14)
130 self.assertEqual(float("+3.14 "), 3.14)
131 self.assertEqual(float("-3.14 "), -3.14)
132 self.assertEqual(float(".14 "), .14)
133 self.assertEqual(float("3. "), 3.0)
134 self.assertEqual(float("3.e3 "), 3000.0)
135 self.assertEqual(float("3.2e3 "), 3200.0)
136 self.assertEqual(float("2.5e-1 "), 0.25)
137 self.assertEqual(float("5e-1"), 0.5)
138 self.assertRaises(ValueError, float, " 3,14 ")
139 self.assertRaises(ValueError, float, " +3,14 ")
140 self.assertRaises(ValueError, float, " -3,14 ")
141 self.assertRaises(ValueError, float, " 0x3.1 ")
142 self.assertRaises(ValueError, float, " -0x3.p-1 ")
143 self.assertRaises(ValueError, float, " +0x3.p-1 ")
144 self.assertEqual(float(" 25.e-1 "), 2.5)
Benjamin Petersond43029b2008-09-06 23:33:21 +0000145 self.assertEqual(support.fcmp(float(" .25e-1 "), .025), 0)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000146
147 def test_floatconversion(self):
148 # Make sure that calls to __float__() work properly
149 class Foo0:
150 def __float__(self):
151 return 42.
152
153 class Foo1(object):
154 def __float__(self):
155 return 42.
156
157 class Foo2(float):
158 def __float__(self):
159 return 42.
160
161 class Foo3(float):
162 def __new__(cls, value=0.):
163 return float.__new__(cls, 2*value)
164
165 def __float__(self):
166 return self
167
168 class Foo4(float):
169 def __float__(self):
170 return 42
171
Benjamin Peterson2808d3c2009-04-15 21:34:27 +0000172 # Issue 5759: __float__ not called on str subclasses (though it is on
173 # unicode subclasses).
174 class FooStr(str):
175 def __float__(self):
176 return float(str(self)) + 1
177
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000178 self.assertAlmostEqual(float(Foo0()), 42.)
179 self.assertAlmostEqual(float(Foo1()), 42.)
180 self.assertAlmostEqual(float(Foo2()), 42.)
181 self.assertAlmostEqual(float(Foo3(21)), 42.)
182 self.assertRaises(TypeError, float, Foo4(42))
Benjamin Peterson2808d3c2009-04-15 21:34:27 +0000183 self.assertAlmostEqual(float(FooStr('8')), 9.)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000184
185 def test_floatasratio(self):
186 for f, ratio in [
187 (0.875, (7, 8)),
188 (-0.875, (-7, 8)),
189 (0.0, (0, 1)),
190 (11.5, (23, 2)),
191 ]:
192 self.assertEqual(f.as_integer_ratio(), ratio)
193
194 for i in range(10000):
195 f = random.random()
196 f *= 10 ** random.randint(-100, 100)
197 n, d = f.as_integer_ratio()
198 self.assertEqual(float(n).__truediv__(d), f)
199
200 R = fractions.Fraction
201 self.assertEqual(R(0, 1),
202 R(*float(0.0).as_integer_ratio()))
203 self.assertEqual(R(5, 2),
204 R(*float(2.5).as_integer_ratio()))
205 self.assertEqual(R(1, 2),
206 R(*float(0.5).as_integer_ratio()))
207 self.assertEqual(R(4728779608739021, 2251799813685248),
208 R(*float(2.1).as_integer_ratio()))
209 self.assertEqual(R(-4728779608739021, 2251799813685248),
210 R(*float(-2.1).as_integer_ratio()))
211 self.assertEqual(R(-2100, 1),
212 R(*float(-2100.0).as_integer_ratio()))
213
214 self.assertRaises(OverflowError, float('inf').as_integer_ratio)
215 self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
216 self.assertRaises(ValueError, float('nan').as_integer_ratio)
217
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000218 def test_float_containment(self):
219 floats = (INF, -INF, 0.0, 1.0, NAN)
220 for f in floats:
Georg Brandlab91fde2009-08-13 08:51:18 +0000221 self.assertTrue(f in [f], "'%r' not in []" % f)
222 self.assertTrue(f in (f,), "'%r' not in ()" % f)
223 self.assertTrue(f in {f}, "'%r' not in set()" % f)
224 self.assertTrue(f in {f: None}, "'%r' not in {}" % f)
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000225 self.assertEqual([f].count(f), 1, "[].count('%r') != 1" % f)
Georg Brandlab91fde2009-08-13 08:51:18 +0000226 self.assertTrue(f in floats, "'%r' not in container" % f)
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000227
228 for f in floats:
229 # nonidentical containers, same type, same contents
Georg Brandlab91fde2009-08-13 08:51:18 +0000230 self.assertTrue([f] == [f], "[%r] != [%r]" % (f, f))
231 self.assertTrue((f,) == (f,), "(%r,) != (%r,)" % (f, f))
232 self.assertTrue({f} == {f}, "{%r} != {%r}" % (f, f))
233 self.assertTrue({f : None} == {f: None}, "{%r : None} != "
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000234 "{%r : None}" % (f, f))
235
236 # identical containers
237 l, t, s, d = [f], (f,), {f}, {f: None}
Georg Brandlab91fde2009-08-13 08:51:18 +0000238 self.assertTrue(l == l, "[%r] not equal to itself" % f)
239 self.assertTrue(t == t, "(%r,) not equal to itself" % f)
240 self.assertTrue(s == s, "{%r} not equal to itself" % f)
241 self.assertTrue(d == d, "{%r : None} not equal to itself" % f)
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000242
Mark Dickinson0169af12010-12-04 13:04:18 +0000243 def assertEqualAndEqualSign(self, a, b):
244 # fail unless a == b and a and b have the same sign bit;
245 # the only difference from assertEqual is that this test
Ezio Melotti13925002011-03-16 11:05:33 +0200246 # distinguishes -0.0 and 0.0.
Mark Dickinson0169af12010-12-04 13:04:18 +0000247 self.assertEqual((a, copysign(1.0, a)), (b, copysign(1.0, b)))
248
249 @requires_IEEE_754
250 def test_float_mod(self):
251 # Check behaviour of % operator for IEEE 754 special cases.
252 # In particular, check signs of zeros.
253 mod = operator.mod
254
255 self.assertEqualAndEqualSign(mod(-1.0, 1.0), 0.0)
256 self.assertEqualAndEqualSign(mod(-1e-100, 1.0), 1.0)
257 self.assertEqualAndEqualSign(mod(-0.0, 1.0), 0.0)
258 self.assertEqualAndEqualSign(mod(0.0, 1.0), 0.0)
259 self.assertEqualAndEqualSign(mod(1e-100, 1.0), 1e-100)
260 self.assertEqualAndEqualSign(mod(1.0, 1.0), 0.0)
261
262 self.assertEqualAndEqualSign(mod(-1.0, -1.0), -0.0)
263 self.assertEqualAndEqualSign(mod(-1e-100, -1.0), -1e-100)
264 self.assertEqualAndEqualSign(mod(-0.0, -1.0), -0.0)
265 self.assertEqualAndEqualSign(mod(0.0, -1.0), -0.0)
266 self.assertEqualAndEqualSign(mod(1e-100, -1.0), -1.0)
267 self.assertEqualAndEqualSign(mod(1.0, -1.0), -0.0)
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000268
269
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000270class FormatFunctionsTestCase(unittest.TestCase):
271
272 def setUp(self):
273 self.save_formats = {'double':float.__getformat__('double'),
274 'float':float.__getformat__('float')}
275
276 def tearDown(self):
277 float.__setformat__('double', self.save_formats['double'])
278 float.__setformat__('float', self.save_formats['float'])
279
280 def test_getformat(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000281 self.assertTrue(float.__getformat__('double') in
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000282 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
Georg Brandlab91fde2009-08-13 08:51:18 +0000283 self.assertTrue(float.__getformat__('float') in
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000284 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
285 self.assertRaises(ValueError, float.__getformat__, 'chicken')
286 self.assertRaises(TypeError, float.__getformat__, 1)
287
288 def test_setformat(self):
289 for t in 'double', 'float':
290 float.__setformat__(t, 'unknown')
291 if self.save_formats[t] == 'IEEE, big-endian':
292 self.assertRaises(ValueError, float.__setformat__,
293 t, 'IEEE, little-endian')
294 elif self.save_formats[t] == 'IEEE, little-endian':
295 self.assertRaises(ValueError, float.__setformat__,
296 t, 'IEEE, big-endian')
297 else:
298 self.assertRaises(ValueError, float.__setformat__,
299 t, 'IEEE, big-endian')
300 self.assertRaises(ValueError, float.__setformat__,
301 t, 'IEEE, little-endian')
302 self.assertRaises(ValueError, float.__setformat__,
303 t, 'chicken')
304 self.assertRaises(ValueError, float.__setformat__,
305 'chicken', 'unknown')
306
Guido van Rossum2be161d2007-05-15 20:43:51 +0000307BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000308LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000309BE_DOUBLE_NAN = b'\x7f\xf8\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000310LE_DOUBLE_NAN = bytes(reversed(BE_DOUBLE_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000311
Guido van Rossum2be161d2007-05-15 20:43:51 +0000312BE_FLOAT_INF = b'\x7f\x80\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000313LE_FLOAT_INF = bytes(reversed(BE_FLOAT_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000314BE_FLOAT_NAN = b'\x7f\xc0\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000315LE_FLOAT_NAN = bytes(reversed(BE_FLOAT_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000316
317# on non-IEEE platforms, attempting to unpack a bit pattern
318# representing an infinity or a NaN should raise an exception.
319
320class UnknownFormatTestCase(unittest.TestCase):
321 def setUp(self):
322 self.save_formats = {'double':float.__getformat__('double'),
323 'float':float.__getformat__('float')}
324 float.__setformat__('double', 'unknown')
325 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000326
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000327 def tearDown(self):
328 float.__setformat__('double', self.save_formats['double'])
329 float.__setformat__('float', self.save_formats['float'])
330
331 def test_double_specials_dont_unpack(self):
332 for fmt, data in [('>d', BE_DOUBLE_INF),
333 ('>d', BE_DOUBLE_NAN),
334 ('<d', LE_DOUBLE_INF),
335 ('<d', LE_DOUBLE_NAN)]:
336 self.assertRaises(ValueError, struct.unpack, fmt, data)
337
338 def test_float_specials_dont_unpack(self):
339 for fmt, data in [('>f', BE_FLOAT_INF),
340 ('>f', BE_FLOAT_NAN),
341 ('<f', LE_FLOAT_INF),
342 ('<f', LE_FLOAT_NAN)]:
343 self.assertRaises(ValueError, struct.unpack, fmt, data)
344
345
346# on an IEEE platform, all we guarantee is that bit patterns
347# representing infinities or NaNs do not raise an exception; all else
348# is accident (today).
Guido van Rossum04110fb2007-08-24 16:32:05 +0000349# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000350
351class IEEEFormatTestCase(unittest.TestCase):
352 if float.__getformat__("double").startswith("IEEE"):
353 def test_double_specials_do_unpack(self):
354 for fmt, data in [('>d', BE_DOUBLE_INF),
355 ('>d', BE_DOUBLE_NAN),
356 ('<d', LE_DOUBLE_INF),
357 ('<d', LE_DOUBLE_NAN)]:
358 struct.unpack(fmt, data)
359
360 if float.__getformat__("float").startswith("IEEE"):
361 def test_float_specials_do_unpack(self):
362 for fmt, data in [('>f', BE_FLOAT_INF),
363 ('>f', BE_FLOAT_NAN),
364 ('<f', LE_FLOAT_INF),
365 ('<f', LE_FLOAT_NAN)]:
366 struct.unpack(fmt, data)
367
Guido van Rossum04110fb2007-08-24 16:32:05 +0000368 if float.__getformat__("double").startswith("IEEE"):
369 def test_negative_zero(self):
370 import math
371 def pos_pos():
372 return 0.0, math.atan2(0.0, -1)
373 def pos_neg():
374 return 0.0, math.atan2(-0.0, -1)
375 def neg_pos():
376 return -0.0, math.atan2(0.0, -1)
377 def neg_neg():
378 return -0.0, math.atan2(-0.0, -1)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000379 self.assertEqual(pos_pos(), neg_pos())
380 self.assertEqual(pos_neg(), neg_neg())
Guido van Rossum04110fb2007-08-24 16:32:05 +0000381
Eric Smith8c663262007-08-25 02:26:07 +0000382class FormatTestCase(unittest.TestCase):
Eric Smith11fe3e02007-08-31 01:33:06 +0000383 def test_format(self):
Eric Smith8c663262007-08-25 02:26:07 +0000384 # these should be rewritten to use both format(x, spec) and
385 # x.__format__(spec)
386
387 self.assertEqual(format(0.0, 'f'), '0.000000')
388
389 # the default is 'g', except for empty format spec
390 self.assertEqual(format(0.0, ''), '0.0')
391 self.assertEqual(format(0.01, ''), '0.01')
392 self.assertEqual(format(0.01, 'g'), '0.01')
393
Eric Smith63376222009-05-05 14:04:18 +0000394 # empty presentation type should format in the same way as str
395 # (issue 5920)
396 x = 100/7.
397 self.assertEqual(format(x, ''), str(x))
398 self.assertEqual(format(x, '-'), str(x))
399 self.assertEqual(format(x, '>'), str(x))
400 self.assertEqual(format(x, '2'), str(x))
Eric Smith8c663262007-08-25 02:26:07 +0000401
402 self.assertEqual(format(1.0, 'f'), '1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000403
404 self.assertEqual(format(-1.0, 'f'), '-1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000405
406 self.assertEqual(format( 1.0, ' f'), ' 1.000000')
407 self.assertEqual(format(-1.0, ' f'), '-1.000000')
408 self.assertEqual(format( 1.0, '+f'), '+1.000000')
409 self.assertEqual(format(-1.0, '+f'), '-1.000000')
410
411 # % formatting
412 self.assertEqual(format(-1.0, '%'), '-100.000000%')
413
414 # conversion to string should fail
415 self.assertRaises(ValueError, format, 3.0, "s")
416
Eric Smith7b69c6c2008-01-27 21:07:59 +0000417 # other format specifiers shouldn't work on floats,
418 # in particular int specifiers
419 for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
420 [chr(x) for x in range(ord('A'), ord('Z')+1)]):
421 if not format_spec in 'eEfFgGn%':
422 self.assertRaises(ValueError, format, 0.0, format_spec)
423 self.assertRaises(ValueError, format, 1.0, format_spec)
424 self.assertRaises(ValueError, format, -1.0, format_spec)
425 self.assertRaises(ValueError, format, 1e100, format_spec)
426 self.assertRaises(ValueError, format, -1e100, format_spec)
427 self.assertRaises(ValueError, format, 1e-100, format_spec)
428 self.assertRaises(ValueError, format, -1e-100, format_spec)
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000429
Eric Smith741191f2009-05-06 13:08:15 +0000430 # issue 3382
431 self.assertEqual(format(NAN, 'f'), 'nan')
432 self.assertEqual(format(NAN, 'F'), 'NAN')
433 self.assertEqual(format(INF, 'f'), 'inf')
434 self.assertEqual(format(INF, 'F'), 'INF')
435
Eric Smith0923d1d2009-04-16 20:16:10 +0000436 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
437 "test requires IEEE 754 doubles")
438 def test_format_testfile(self):
Brian Curtina813a632010-10-31 00:05:24 +0000439 with open(format_testfile) as testfile:
440 for line in testfile:
441 if line.startswith('--'):
442 continue
443 line = line.strip()
444 if not line:
445 continue
Eric Smith0923d1d2009-04-16 20:16:10 +0000446
Brian Curtina813a632010-10-31 00:05:24 +0000447 lhs, rhs = map(str.strip, line.split('->'))
448 fmt, arg = lhs.split()
449 self.assertEqual(fmt % float(arg), rhs)
450 self.assertEqual(fmt % -float(arg), '-' + rhs)
Eric Smith0923d1d2009-04-16 20:16:10 +0000451
Mark Dickinsond3ca5572009-04-29 18:47:07 +0000452 def test_issue5864(self):
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000453 self.assertEqual(format(123.456, '.4'), '123.5')
454 self.assertEqual(format(1234.56, '.4'), '1.235e+03')
455 self.assertEqual(format(12345.6, '.4'), '1.235e+04')
Mark Dickinsond3ca5572009-04-29 18:47:07 +0000456
Mark Dickinson7efad9e2009-04-17 20:59:58 +0000457class ReprTestCase(unittest.TestCase):
458 def test_repr(self):
459 floats_file = open(os.path.join(os.path.split(__file__)[0],
460 'floating_points.txt'))
461 for line in floats_file:
462 line = line.strip()
463 if not line or line.startswith('#'):
464 continue
465 v = eval(line)
466 self.assertEqual(v, eval(repr(v)))
467 floats_file.close()
468
Eric Smith0923d1d2009-04-16 20:16:10 +0000469 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
470 "applies only when using short float repr style")
471 def test_short_repr(self):
472 # test short float repr introduced in Python 3.1. One aspect
473 # of this repr is that we get some degree of str -> float ->
474 # str roundtripping. In particular, for any numeric string
475 # containing 15 or fewer significant digits, those exact same
476 # digits (modulo trailing zeros) should appear in the output.
477 # No more repr(0.03) -> "0.029999999999999999"!
478
479 test_strings = [
480 # output always includes *either* a decimal point and at
481 # least one digit after that point, or an exponent.
482 '0.0',
483 '1.0',
484 '0.01',
485 '0.02',
486 '0.03',
487 '0.04',
488 '0.05',
489 '1.23456789',
490 '10.0',
491 '100.0',
492 # values >= 1e16 get an exponent...
493 '1000000000000000.0',
494 '9999999999999990.0',
495 '1e+16',
496 '1e+17',
497 # ... and so do values < 1e-4
498 '0.001',
499 '0.001001',
500 '0.00010000000000001',
501 '0.0001',
502 '9.999999999999e-05',
503 '1e-05',
504 # values designed to provoke failure if the FPU rounding
505 # precision isn't set correctly
506 '8.72293771110361e+25',
507 '7.47005307342313e+26',
508 '2.86438000439698e+28',
509 '8.89142905246179e+28',
510 '3.08578087079232e+35',
511 ]
512
513 for s in test_strings:
514 negs = '-'+s
515 self.assertEqual(s, repr(float(s)))
516 self.assertEqual(negs, repr(float(negs)))
517
Mark Dickinsone6a076d2009-04-18 11:48:33 +0000518class RoundTestCase(unittest.TestCase):
519 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
520 "test requires IEEE 754 doubles")
521 def test_inf_nan(self):
522 self.assertRaises(OverflowError, round, INF)
523 self.assertRaises(OverflowError, round, -INF)
524 self.assertRaises(ValueError, round, NAN)
Mark Dickinsonae31a7c2009-11-24 11:00:21 +0000525 self.assertRaises(TypeError, round, INF, 0.0)
526 self.assertRaises(TypeError, round, -INF, 1.0)
527 self.assertRaises(TypeError, round, NAN, "ceci n'est pas un integer")
528 self.assertRaises(TypeError, round, -0.0, 1j)
Mark Dickinsone6a076d2009-04-18 11:48:33 +0000529
530 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
531 "test requires IEEE 754 doubles")
532 def test_large_n(self):
533 for n in [324, 325, 400, 2**31-1, 2**31, 2**32, 2**100]:
534 self.assertEqual(round(123.456, n), 123.456)
535 self.assertEqual(round(-123.456, n), -123.456)
536 self.assertEqual(round(1e300, n), 1e300)
537 self.assertEqual(round(1e-320, n), 1e-320)
538 self.assertEqual(round(1e150, 300), 1e150)
539 self.assertEqual(round(1e300, 307), 1e300)
540 self.assertEqual(round(-3.1415, 308), -3.1415)
541 self.assertEqual(round(1e150, 309), 1e150)
542 self.assertEqual(round(1.4e-315, 315), 1e-315)
543
544 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
545 "test requires IEEE 754 doubles")
546 def test_small_n(self):
547 for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]:
548 self.assertEqual(round(123.456, n), 0.0)
549 self.assertEqual(round(-123.456, n), -0.0)
550 self.assertEqual(round(1e300, n), 0.0)
551 self.assertEqual(round(1e-320, n), 0.0)
552
553 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
554 "test requires IEEE 754 doubles")
555 def test_overflow(self):
556 self.assertRaises(OverflowError, round, 1.6e308, -308)
557 self.assertRaises(OverflowError, round, -1.7e308, -308)
558
559 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
560 "applies only when using short float repr style")
561 def test_previous_round_bugs(self):
562 # particular cases that have occurred in bug reports
563 self.assertEqual(round(562949953421312.5, 1),
564 562949953421312.5)
565 self.assertEqual(round(56294995342131.5, 3),
566 56294995342131.5)
567 # round-half-even
568 self.assertEqual(round(25.0, -1), 20.0)
569 self.assertEqual(round(35.0, -1), 40.0)
570 self.assertEqual(round(45.0, -1), 40.0)
571 self.assertEqual(round(55.0, -1), 60.0)
572 self.assertEqual(round(65.0, -1), 60.0)
573 self.assertEqual(round(75.0, -1), 80.0)
574 self.assertEqual(round(85.0, -1), 80.0)
575 self.assertEqual(round(95.0, -1), 100.0)
576
577 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
578 "applies only when using short float repr style")
579 def test_matches_float_format(self):
580 # round should give the same results as float formatting
581 for i in range(500):
582 x = i/1000.
583 self.assertEqual(float(format(x, '.0f')), round(x, 0))
584 self.assertEqual(float(format(x, '.1f')), round(x, 1))
585 self.assertEqual(float(format(x, '.2f')), round(x, 2))
586 self.assertEqual(float(format(x, '.3f')), round(x, 3))
587
588 for i in range(5, 5000, 10):
589 x = i/1000.
590 self.assertEqual(float(format(x, '.0f')), round(x, 0))
591 self.assertEqual(float(format(x, '.1f')), round(x, 1))
592 self.assertEqual(float(format(x, '.2f')), round(x, 2))
593 self.assertEqual(float(format(x, '.3f')), round(x, 3))
594
595 for i in range(500):
596 x = random.random()
597 self.assertEqual(float(format(x, '.0f')), round(x, 0))
598 self.assertEqual(float(format(x, '.1f')), round(x, 1))
599 self.assertEqual(float(format(x, '.2f')), round(x, 2))
600 self.assertEqual(float(format(x, '.3f')), round(x, 3))
601
602
603
Christian Heimes99170a52007-12-19 02:07:34 +0000604# Beginning with Python 2.6 float has cross platform compatible
Georg Brandl2ee470f2008-07-16 12:55:28 +0000605# ways to create and represent inf and nan
Christian Heimes99170a52007-12-19 02:07:34 +0000606class InfNanTest(unittest.TestCase):
607 def test_inf_from_str(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000608 self.assertTrue(isinf(float("inf")))
609 self.assertTrue(isinf(float("+inf")))
610 self.assertTrue(isinf(float("-inf")))
611 self.assertTrue(isinf(float("infinity")))
612 self.assertTrue(isinf(float("+infinity")))
613 self.assertTrue(isinf(float("-infinity")))
Christian Heimes99170a52007-12-19 02:07:34 +0000614
615 self.assertEqual(repr(float("inf")), "inf")
616 self.assertEqual(repr(float("+inf")), "inf")
617 self.assertEqual(repr(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000618 self.assertEqual(repr(float("infinity")), "inf")
619 self.assertEqual(repr(float("+infinity")), "inf")
620 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000621
622 self.assertEqual(repr(float("INF")), "inf")
623 self.assertEqual(repr(float("+Inf")), "inf")
624 self.assertEqual(repr(float("-iNF")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000625 self.assertEqual(repr(float("Infinity")), "inf")
626 self.assertEqual(repr(float("+iNfInItY")), "inf")
627 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000628
629 self.assertEqual(str(float("inf")), "inf")
630 self.assertEqual(str(float("+inf")), "inf")
631 self.assertEqual(str(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000632 self.assertEqual(str(float("infinity")), "inf")
633 self.assertEqual(str(float("+infinity")), "inf")
634 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000635
636 self.assertRaises(ValueError, float, "info")
637 self.assertRaises(ValueError, float, "+info")
638 self.assertRaises(ValueError, float, "-info")
639 self.assertRaises(ValueError, float, "in")
640 self.assertRaises(ValueError, float, "+in")
641 self.assertRaises(ValueError, float, "-in")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000642 self.assertRaises(ValueError, float, "infinit")
643 self.assertRaises(ValueError, float, "+Infin")
644 self.assertRaises(ValueError, float, "-INFI")
645 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes99170a52007-12-19 02:07:34 +0000646
Mark Dickinsonbd16edd2009-05-20 22:05:25 +0000647 self.assertRaises(ValueError, float, "++Inf")
648 self.assertRaises(ValueError, float, "-+inf")
649 self.assertRaises(ValueError, float, "+-infinity")
650 self.assertRaises(ValueError, float, "--Infinity")
651
Christian Heimes99170a52007-12-19 02:07:34 +0000652 def test_inf_as_str(self):
653 self.assertEqual(repr(1e300 * 1e300), "inf")
654 self.assertEqual(repr(-1e300 * 1e300), "-inf")
655
656 self.assertEqual(str(1e300 * 1e300), "inf")
657 self.assertEqual(str(-1e300 * 1e300), "-inf")
658
659 def test_nan_from_str(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000660 self.assertTrue(isnan(float("nan")))
661 self.assertTrue(isnan(float("+nan")))
662 self.assertTrue(isnan(float("-nan")))
Christian Heimes99170a52007-12-19 02:07:34 +0000663
664 self.assertEqual(repr(float("nan")), "nan")
665 self.assertEqual(repr(float("+nan")), "nan")
666 self.assertEqual(repr(float("-nan")), "nan")
667
668 self.assertEqual(repr(float("NAN")), "nan")
669 self.assertEqual(repr(float("+NAn")), "nan")
670 self.assertEqual(repr(float("-NaN")), "nan")
671
672 self.assertEqual(str(float("nan")), "nan")
673 self.assertEqual(str(float("+nan")), "nan")
674 self.assertEqual(str(float("-nan")), "nan")
675
676 self.assertRaises(ValueError, float, "nana")
677 self.assertRaises(ValueError, float, "+nana")
678 self.assertRaises(ValueError, float, "-nana")
679 self.assertRaises(ValueError, float, "na")
680 self.assertRaises(ValueError, float, "+na")
681 self.assertRaises(ValueError, float, "-na")
682
Mark Dickinsonbd16edd2009-05-20 22:05:25 +0000683 self.assertRaises(ValueError, float, "++nan")
684 self.assertRaises(ValueError, float, "-+NAN")
685 self.assertRaises(ValueError, float, "+-NaN")
686 self.assertRaises(ValueError, float, "--nAn")
687
Christian Heimes99170a52007-12-19 02:07:34 +0000688 def test_nan_as_str(self):
689 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
690 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
691
692 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
693 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes827b35c2007-12-10 22:19:17 +0000694
Christian Heimes53876d92008-04-19 00:31:39 +0000695 def notest_float_nan(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000696 self.assertTrue(NAN.is_nan())
697 self.assertFalse(INF.is_nan())
698 self.assertFalse((0.).is_nan())
Christian Heimes53876d92008-04-19 00:31:39 +0000699
700 def notest_float_inf(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000701 self.assertTrue(INF.is_inf())
702 self.assertFalse(NAN.is_inf())
703 self.assertFalse((0.).is_inf())
Christian Heimes53876d92008-04-19 00:31:39 +0000704
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000705fromHex = float.fromhex
706toHex = float.hex
707class HexFloatTestCase(unittest.TestCase):
708 MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
709 MIN = fromHex('0x1p-1022') # min normal
710 TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
711 EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
712
713 def identical(self, x, y):
714 # check that floats x and y are identical, or that both
715 # are NaNs
716 if isnan(x) or isnan(y):
717 if isnan(x) == isnan(y):
718 return
719 elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
720 return
721 self.fail('%r not identical to %r' % (x, y))
722
723 def test_ends(self):
Mark Dickinson38bbc482008-07-16 11:32:23 +0000724 self.identical(self.MIN, ldexp(1.0, -1022))
725 self.identical(self.TINY, ldexp(1.0, -1074))
726 self.identical(self.EPS, ldexp(1.0, -52))
727 self.identical(self.MAX, 2.*(ldexp(1.0, 1023) - ldexp(1.0, 970)))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000728
729 def test_invalid_inputs(self):
730 invalid_inputs = [
731 'infi', # misspelt infinities and nans
732 '-Infinit',
733 '++inf',
734 '-+Inf',
735 '--nan',
736 '+-NaN',
737 'snan',
738 'NaNs',
739 'nna',
Mark Dickinsond1ec8b22009-05-11 15:45:15 +0000740 'an',
741 'nf',
742 'nfinity',
743 'inity',
744 'iinity',
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000745 '0xnan',
746 '',
747 ' ',
748 'x1.0p0',
749 '0xX1.0p0',
750 '+ 0x1.0p0', # internal whitespace
751 '- 0x1.0p0',
752 '0 x1.0p0',
753 '0x 1.0p0',
754 '0x1 2.0p0',
755 '+0x1 .0p0',
756 '0x1. 0p0',
757 '-0x1.0 1p0',
758 '-0x1.0 p0',
759 '+0x1.0p +0',
760 '0x1.0p -0',
761 '0x1.0p 0',
762 '+0x1.0p+ 0',
763 '-0x1.0p- 0',
764 '++0x1.0p-0', # double signs
765 '--0x1.0p0',
766 '+-0x1.0p+0',
767 '-+0x1.0p0',
768 '0x1.0p++0',
769 '+0x1.0p+-0',
770 '-0x1.0p-+0',
771 '0x1.0p--0',
772 '0x1.0.p0',
773 '0x.p0', # no hex digits before or after point
774 '0x1,p0', # wrong decimal point character
775 '0x1pa',
776 '0x1p\uff10', # fullwidth Unicode digits
777 '\uff10x1p0',
778 '0x\uff11p0',
779 '0x1.\uff10p0',
780 '0x1p0 \n 0x2p0',
781 '0x1p0\0 0x1p0', # embedded null byte is not end of string
782 ]
783 for x in invalid_inputs:
Mark Dickinson589b7952008-08-21 20:05:56 +0000784 try:
785 result = fromHex(x)
786 except ValueError:
787 pass
788 else:
789 self.fail('Expected float.fromhex(%r) to raise ValueError; '
790 'got %r instead' % (x, result))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000791
792
Mark Dickinsond1ec8b22009-05-11 15:45:15 +0000793 def test_whitespace(self):
794 value_pairs = [
795 ('inf', INF),
796 ('-Infinity', -INF),
797 ('nan', NAN),
798 ('1.0', 1.0),
799 ('-0x.2', -0.125),
800 ('-0.0', -0.0)
801 ]
802 whitespace = [
803 '',
804 ' ',
805 '\t',
806 '\n',
807 '\n \t',
808 '\f',
809 '\v',
810 '\r'
811 ]
812 for inp, expected in value_pairs:
813 for lead in whitespace:
814 for trail in whitespace:
815 got = fromHex(lead + inp + trail)
816 self.identical(got, expected)
817
818
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000819 def test_from_hex(self):
820 MIN = self.MIN;
821 MAX = self.MAX;
822 TINY = self.TINY;
823 EPS = self.EPS;
824
825 # two spellings of infinity, with optional signs; case-insensitive
826 self.identical(fromHex('inf'), INF)
827 self.identical(fromHex('+Inf'), INF)
828 self.identical(fromHex('-INF'), -INF)
829 self.identical(fromHex('iNf'), INF)
830 self.identical(fromHex('Infinity'), INF)
831 self.identical(fromHex('+INFINITY'), INF)
832 self.identical(fromHex('-infinity'), -INF)
833 self.identical(fromHex('-iNFiNitY'), -INF)
834
835 # nans with optional sign; case insensitive
836 self.identical(fromHex('nan'), NAN)
837 self.identical(fromHex('+NaN'), NAN)
838 self.identical(fromHex('-NaN'), NAN)
839 self.identical(fromHex('-nAN'), NAN)
840
841 # variations in input format
842 self.identical(fromHex('1'), 1.0)
843 self.identical(fromHex('+1'), 1.0)
844 self.identical(fromHex('1.'), 1.0)
845 self.identical(fromHex('1.0'), 1.0)
846 self.identical(fromHex('1.0p0'), 1.0)
847 self.identical(fromHex('01'), 1.0)
848 self.identical(fromHex('01.'), 1.0)
849 self.identical(fromHex('0x1'), 1.0)
850 self.identical(fromHex('0x1.'), 1.0)
851 self.identical(fromHex('0x1.0'), 1.0)
852 self.identical(fromHex('+0x1.0'), 1.0)
853 self.identical(fromHex('0x1p0'), 1.0)
854 self.identical(fromHex('0X1p0'), 1.0)
855 self.identical(fromHex('0X1P0'), 1.0)
856 self.identical(fromHex('0x1P0'), 1.0)
857 self.identical(fromHex('0x1.p0'), 1.0)
858 self.identical(fromHex('0x1.0p0'), 1.0)
859 self.identical(fromHex('0x.1p4'), 1.0)
860 self.identical(fromHex('0x.1p04'), 1.0)
861 self.identical(fromHex('0x.1p004'), 1.0)
862 self.identical(fromHex('0x1p+0'), 1.0)
863 self.identical(fromHex('0x1P-0'), 1.0)
864 self.identical(fromHex('+0x1p0'), 1.0)
865 self.identical(fromHex('0x01p0'), 1.0)
866 self.identical(fromHex('0x1p00'), 1.0)
867 self.identical(fromHex(' 0x1p0 '), 1.0)
868 self.identical(fromHex('\n 0x1p0'), 1.0)
869 self.identical(fromHex('0x1p0 \t'), 1.0)
870 self.identical(fromHex('0xap0'), 10.0)
871 self.identical(fromHex('0xAp0'), 10.0)
872 self.identical(fromHex('0xaP0'), 10.0)
873 self.identical(fromHex('0xAP0'), 10.0)
874 self.identical(fromHex('0xbep0'), 190.0)
875 self.identical(fromHex('0xBep0'), 190.0)
876 self.identical(fromHex('0xbEp0'), 190.0)
877 self.identical(fromHex('0XBE0P-4'), 190.0)
878 self.identical(fromHex('0xBEp0'), 190.0)
879 self.identical(fromHex('0xB.Ep4'), 190.0)
880 self.identical(fromHex('0x.BEp8'), 190.0)
881 self.identical(fromHex('0x.0BEp12'), 190.0)
882
883 # moving the point around
884 pi = fromHex('0x1.921fb54442d18p1')
885 self.identical(fromHex('0x.006487ed5110b46p11'), pi)
886 self.identical(fromHex('0x.00c90fdaa22168cp10'), pi)
887 self.identical(fromHex('0x.01921fb54442d18p9'), pi)
888 self.identical(fromHex('0x.03243f6a8885a3p8'), pi)
889 self.identical(fromHex('0x.06487ed5110b46p7'), pi)
890 self.identical(fromHex('0x.0c90fdaa22168cp6'), pi)
891 self.identical(fromHex('0x.1921fb54442d18p5'), pi)
892 self.identical(fromHex('0x.3243f6a8885a3p4'), pi)
893 self.identical(fromHex('0x.6487ed5110b46p3'), pi)
894 self.identical(fromHex('0x.c90fdaa22168cp2'), pi)
895 self.identical(fromHex('0x1.921fb54442d18p1'), pi)
896 self.identical(fromHex('0x3.243f6a8885a3p0'), pi)
897 self.identical(fromHex('0x6.487ed5110b46p-1'), pi)
898 self.identical(fromHex('0xc.90fdaa22168cp-2'), pi)
899 self.identical(fromHex('0x19.21fb54442d18p-3'), pi)
900 self.identical(fromHex('0x32.43f6a8885a3p-4'), pi)
901 self.identical(fromHex('0x64.87ed5110b46p-5'), pi)
902 self.identical(fromHex('0xc9.0fdaa22168cp-6'), pi)
903 self.identical(fromHex('0x192.1fb54442d18p-7'), pi)
904 self.identical(fromHex('0x324.3f6a8885a3p-8'), pi)
905 self.identical(fromHex('0x648.7ed5110b46p-9'), pi)
906 self.identical(fromHex('0xc90.fdaa22168cp-10'), pi)
907 self.identical(fromHex('0x1921.fb54442d18p-11'), pi)
908 # ...
909 self.identical(fromHex('0x1921fb54442d1.8p-47'), pi)
910 self.identical(fromHex('0x3243f6a8885a3p-48'), pi)
911 self.identical(fromHex('0x6487ed5110b46p-49'), pi)
912 self.identical(fromHex('0xc90fdaa22168cp-50'), pi)
913 self.identical(fromHex('0x1921fb54442d18p-51'), pi)
914 self.identical(fromHex('0x3243f6a8885a30p-52'), pi)
915 self.identical(fromHex('0x6487ed5110b460p-53'), pi)
916 self.identical(fromHex('0xc90fdaa22168c0p-54'), pi)
917 self.identical(fromHex('0x1921fb54442d180p-55'), pi)
918
919
920 # results that should overflow...
921 self.assertRaises(OverflowError, fromHex, '-0x1p1024')
922 self.assertRaises(OverflowError, fromHex, '0x1p+1025')
923 self.assertRaises(OverflowError, fromHex, '+0X1p1030')
924 self.assertRaises(OverflowError, fromHex, '-0x1p+1100')
925 self.assertRaises(OverflowError, fromHex, '0X1p123456789123456789')
926 self.assertRaises(OverflowError, fromHex, '+0X.8p+1025')
927 self.assertRaises(OverflowError, fromHex, '+0x0.8p1025')
928 self.assertRaises(OverflowError, fromHex, '-0x0.4p1026')
929 self.assertRaises(OverflowError, fromHex, '0X2p+1023')
930 self.assertRaises(OverflowError, fromHex, '0x2.p1023')
931 self.assertRaises(OverflowError, fromHex, '-0x2.0p+1023')
932 self.assertRaises(OverflowError, fromHex, '+0X4p+1022')
933 self.assertRaises(OverflowError, fromHex, '0x1.ffffffffffffffp+1023')
934 self.assertRaises(OverflowError, fromHex, '-0X1.fffffffffffff9p1023')
935 self.assertRaises(OverflowError, fromHex, '0X1.fffffffffffff8p1023')
936 self.assertRaises(OverflowError, fromHex, '+0x3.fffffffffffffp1022')
937 self.assertRaises(OverflowError, fromHex, '0x3fffffffffffffp+970')
938 self.assertRaises(OverflowError, fromHex, '0x10000000000000000p960')
939 self.assertRaises(OverflowError, fromHex, '-0Xffffffffffffffffp960')
940
941 # ...and those that round to +-max float
942 self.identical(fromHex('+0x1.fffffffffffffp+1023'), MAX)
943 self.identical(fromHex('-0X1.fffffffffffff7p1023'), -MAX)
944 self.identical(fromHex('0X1.fffffffffffff7fffffffffffffp1023'), MAX)
945
946 # zeros
947 self.identical(fromHex('0x0p0'), 0.0)
948 self.identical(fromHex('0x0p1000'), 0.0)
949 self.identical(fromHex('-0x0p1023'), -0.0)
950 self.identical(fromHex('0X0p1024'), 0.0)
951 self.identical(fromHex('-0x0p1025'), -0.0)
952 self.identical(fromHex('0X0p2000'), 0.0)
953 self.identical(fromHex('0x0p123456789123456789'), 0.0)
954 self.identical(fromHex('-0X0p-0'), -0.0)
955 self.identical(fromHex('-0X0p-1000'), -0.0)
956 self.identical(fromHex('0x0p-1023'), 0.0)
957 self.identical(fromHex('-0X0p-1024'), -0.0)
958 self.identical(fromHex('-0x0p-1025'), -0.0)
959 self.identical(fromHex('-0x0p-1072'), -0.0)
960 self.identical(fromHex('0X0p-1073'), 0.0)
961 self.identical(fromHex('-0x0p-1074'), -0.0)
962 self.identical(fromHex('0x0p-1075'), 0.0)
963 self.identical(fromHex('0X0p-1076'), 0.0)
964 self.identical(fromHex('-0X0p-2000'), -0.0)
965 self.identical(fromHex('-0x0p-123456789123456789'), -0.0)
966
967 # values that should underflow to 0
968 self.identical(fromHex('0X1p-1075'), 0.0)
969 self.identical(fromHex('-0X1p-1075'), -0.0)
970 self.identical(fromHex('-0x1p-123456789123456789'), -0.0)
971 self.identical(fromHex('0x1.00000000000000001p-1075'), TINY)
972 self.identical(fromHex('-0x1.1p-1075'), -TINY)
973 self.identical(fromHex('0x1.fffffffffffffffffp-1075'), TINY)
974
975 # check round-half-even is working correctly near 0 ...
976 self.identical(fromHex('0x1p-1076'), 0.0)
977 self.identical(fromHex('0X2p-1076'), 0.0)
978 self.identical(fromHex('0X3p-1076'), TINY)
979 self.identical(fromHex('0x4p-1076'), TINY)
980 self.identical(fromHex('0X5p-1076'), TINY)
981 self.identical(fromHex('0X6p-1076'), 2*TINY)
982 self.identical(fromHex('0x7p-1076'), 2*TINY)
983 self.identical(fromHex('0X8p-1076'), 2*TINY)
984 self.identical(fromHex('0X9p-1076'), 2*TINY)
985 self.identical(fromHex('0xap-1076'), 2*TINY)
986 self.identical(fromHex('0Xbp-1076'), 3*TINY)
987 self.identical(fromHex('0xcp-1076'), 3*TINY)
988 self.identical(fromHex('0Xdp-1076'), 3*TINY)
989 self.identical(fromHex('0Xep-1076'), 4*TINY)
990 self.identical(fromHex('0xfp-1076'), 4*TINY)
991 self.identical(fromHex('0x10p-1076'), 4*TINY)
992 self.identical(fromHex('-0x1p-1076'), -0.0)
993 self.identical(fromHex('-0X2p-1076'), -0.0)
994 self.identical(fromHex('-0x3p-1076'), -TINY)
995 self.identical(fromHex('-0X4p-1076'), -TINY)
996 self.identical(fromHex('-0x5p-1076'), -TINY)
997 self.identical(fromHex('-0x6p-1076'), -2*TINY)
998 self.identical(fromHex('-0X7p-1076'), -2*TINY)
999 self.identical(fromHex('-0X8p-1076'), -2*TINY)
1000 self.identical(fromHex('-0X9p-1076'), -2*TINY)
1001 self.identical(fromHex('-0Xap-1076'), -2*TINY)
1002 self.identical(fromHex('-0xbp-1076'), -3*TINY)
1003 self.identical(fromHex('-0xcp-1076'), -3*TINY)
1004 self.identical(fromHex('-0Xdp-1076'), -3*TINY)
1005 self.identical(fromHex('-0xep-1076'), -4*TINY)
1006 self.identical(fromHex('-0Xfp-1076'), -4*TINY)
1007 self.identical(fromHex('-0X10p-1076'), -4*TINY)
1008
1009 # ... and near MIN ...
1010 self.identical(fromHex('0x0.ffffffffffffd6p-1022'), MIN-3*TINY)
1011 self.identical(fromHex('0x0.ffffffffffffd8p-1022'), MIN-2*TINY)
1012 self.identical(fromHex('0x0.ffffffffffffdap-1022'), MIN-2*TINY)
1013 self.identical(fromHex('0x0.ffffffffffffdcp-1022'), MIN-2*TINY)
1014 self.identical(fromHex('0x0.ffffffffffffdep-1022'), MIN-2*TINY)
1015 self.identical(fromHex('0x0.ffffffffffffe0p-1022'), MIN-2*TINY)
1016 self.identical(fromHex('0x0.ffffffffffffe2p-1022'), MIN-2*TINY)
1017 self.identical(fromHex('0x0.ffffffffffffe4p-1022'), MIN-2*TINY)
1018 self.identical(fromHex('0x0.ffffffffffffe6p-1022'), MIN-2*TINY)
1019 self.identical(fromHex('0x0.ffffffffffffe8p-1022'), MIN-2*TINY)
1020 self.identical(fromHex('0x0.ffffffffffffeap-1022'), MIN-TINY)
1021 self.identical(fromHex('0x0.ffffffffffffecp-1022'), MIN-TINY)
1022 self.identical(fromHex('0x0.ffffffffffffeep-1022'), MIN-TINY)
1023 self.identical(fromHex('0x0.fffffffffffff0p-1022'), MIN-TINY)
1024 self.identical(fromHex('0x0.fffffffffffff2p-1022'), MIN-TINY)
1025 self.identical(fromHex('0x0.fffffffffffff4p-1022'), MIN-TINY)
1026 self.identical(fromHex('0x0.fffffffffffff6p-1022'), MIN-TINY)
1027 self.identical(fromHex('0x0.fffffffffffff8p-1022'), MIN)
1028 self.identical(fromHex('0x0.fffffffffffffap-1022'), MIN)
1029 self.identical(fromHex('0x0.fffffffffffffcp-1022'), MIN)
1030 self.identical(fromHex('0x0.fffffffffffffep-1022'), MIN)
1031 self.identical(fromHex('0x1.00000000000000p-1022'), MIN)
1032 self.identical(fromHex('0x1.00000000000002p-1022'), MIN)
1033 self.identical(fromHex('0x1.00000000000004p-1022'), MIN)
1034 self.identical(fromHex('0x1.00000000000006p-1022'), MIN)
1035 self.identical(fromHex('0x1.00000000000008p-1022'), MIN)
1036 self.identical(fromHex('0x1.0000000000000ap-1022'), MIN+TINY)
1037 self.identical(fromHex('0x1.0000000000000cp-1022'), MIN+TINY)
1038 self.identical(fromHex('0x1.0000000000000ep-1022'), MIN+TINY)
1039 self.identical(fromHex('0x1.00000000000010p-1022'), MIN+TINY)
1040 self.identical(fromHex('0x1.00000000000012p-1022'), MIN+TINY)
1041 self.identical(fromHex('0x1.00000000000014p-1022'), MIN+TINY)
1042 self.identical(fromHex('0x1.00000000000016p-1022'), MIN+TINY)
1043 self.identical(fromHex('0x1.00000000000018p-1022'), MIN+2*TINY)
1044
1045 # ... and near 1.0.
1046 self.identical(fromHex('0x0.fffffffffffff0p0'), 1.0-EPS)
1047 self.identical(fromHex('0x0.fffffffffffff1p0'), 1.0-EPS)
1048 self.identical(fromHex('0X0.fffffffffffff2p0'), 1.0-EPS)
1049 self.identical(fromHex('0x0.fffffffffffff3p0'), 1.0-EPS)
1050 self.identical(fromHex('0X0.fffffffffffff4p0'), 1.0-EPS)
1051 self.identical(fromHex('0X0.fffffffffffff5p0'), 1.0-EPS/2)
1052 self.identical(fromHex('0X0.fffffffffffff6p0'), 1.0-EPS/2)
1053 self.identical(fromHex('0x0.fffffffffffff7p0'), 1.0-EPS/2)
1054 self.identical(fromHex('0x0.fffffffffffff8p0'), 1.0-EPS/2)
1055 self.identical(fromHex('0X0.fffffffffffff9p0'), 1.0-EPS/2)
1056 self.identical(fromHex('0X0.fffffffffffffap0'), 1.0-EPS/2)
1057 self.identical(fromHex('0x0.fffffffffffffbp0'), 1.0-EPS/2)
1058 self.identical(fromHex('0X0.fffffffffffffcp0'), 1.0)
1059 self.identical(fromHex('0x0.fffffffffffffdp0'), 1.0)
1060 self.identical(fromHex('0X0.fffffffffffffep0'), 1.0)
1061 self.identical(fromHex('0x0.ffffffffffffffp0'), 1.0)
1062 self.identical(fromHex('0X1.00000000000000p0'), 1.0)
1063 self.identical(fromHex('0X1.00000000000001p0'), 1.0)
1064 self.identical(fromHex('0x1.00000000000002p0'), 1.0)
1065 self.identical(fromHex('0X1.00000000000003p0'), 1.0)
1066 self.identical(fromHex('0x1.00000000000004p0'), 1.0)
1067 self.identical(fromHex('0X1.00000000000005p0'), 1.0)
1068 self.identical(fromHex('0X1.00000000000006p0'), 1.0)
1069 self.identical(fromHex('0X1.00000000000007p0'), 1.0)
1070 self.identical(fromHex('0x1.00000000000007ffffffffffffffffffffp0'),
1071 1.0)
1072 self.identical(fromHex('0x1.00000000000008p0'), 1.0)
1073 self.identical(fromHex('0x1.00000000000008000000000000000001p0'),
1074 1+EPS)
1075 self.identical(fromHex('0X1.00000000000009p0'), 1.0+EPS)
1076 self.identical(fromHex('0x1.0000000000000ap0'), 1.0+EPS)
1077 self.identical(fromHex('0x1.0000000000000bp0'), 1.0+EPS)
1078 self.identical(fromHex('0X1.0000000000000cp0'), 1.0+EPS)
1079 self.identical(fromHex('0x1.0000000000000dp0'), 1.0+EPS)
1080 self.identical(fromHex('0x1.0000000000000ep0'), 1.0+EPS)
1081 self.identical(fromHex('0X1.0000000000000fp0'), 1.0+EPS)
1082 self.identical(fromHex('0x1.00000000000010p0'), 1.0+EPS)
1083 self.identical(fromHex('0X1.00000000000011p0'), 1.0+EPS)
1084 self.identical(fromHex('0x1.00000000000012p0'), 1.0+EPS)
1085 self.identical(fromHex('0X1.00000000000013p0'), 1.0+EPS)
1086 self.identical(fromHex('0X1.00000000000014p0'), 1.0+EPS)
1087 self.identical(fromHex('0x1.00000000000015p0'), 1.0+EPS)
1088 self.identical(fromHex('0x1.00000000000016p0'), 1.0+EPS)
1089 self.identical(fromHex('0X1.00000000000017p0'), 1.0+EPS)
1090 self.identical(fromHex('0x1.00000000000017ffffffffffffffffffffp0'),
1091 1.0+EPS)
1092 self.identical(fromHex('0x1.00000000000018p0'), 1.0+2*EPS)
1093 self.identical(fromHex('0X1.00000000000018000000000000000001p0'),
1094 1.0+2*EPS)
1095 self.identical(fromHex('0x1.00000000000019p0'), 1.0+2*EPS)
1096 self.identical(fromHex('0X1.0000000000001ap0'), 1.0+2*EPS)
1097 self.identical(fromHex('0X1.0000000000001bp0'), 1.0+2*EPS)
1098 self.identical(fromHex('0x1.0000000000001cp0'), 1.0+2*EPS)
1099 self.identical(fromHex('0x1.0000000000001dp0'), 1.0+2*EPS)
1100 self.identical(fromHex('0x1.0000000000001ep0'), 1.0+2*EPS)
1101 self.identical(fromHex('0X1.0000000000001fp0'), 1.0+2*EPS)
1102 self.identical(fromHex('0x1.00000000000020p0'), 1.0+2*EPS)
1103
1104 def test_roundtrip(self):
1105 def roundtrip(x):
1106 return fromHex(toHex(x))
1107
1108 for x in [NAN, INF, self.MAX, self.MIN, self.MIN-self.TINY, self.TINY, 0.0]:
1109 self.identical(x, roundtrip(x))
1110 self.identical(-x, roundtrip(-x))
1111
1112 # fromHex(toHex(x)) should exactly recover x, for any non-NaN float x.
1113 import random
1114 for i in range(10000):
1115 e = random.randrange(-1200, 1200)
1116 m = random.random()
1117 s = random.choice([1.0, -1.0])
1118 try:
1119 x = s*ldexp(m, e)
1120 except OverflowError:
1121 pass
1122 else:
1123 self.identical(x, fromHex(toHex(x)))
1124
Mark Dickinson46672512010-01-12 23:09:26 +00001125class StrtodTestCase(unittest.TestCase):
1126 def check_string(self, s):
1127 expected = strtod(s)
1128 try:
1129 fs = float(s)
1130 except OverflowError:
1131 got = '-inf' if s[0] == '-' else 'inf'
1132 else:
1133 got = fs.hex()
1134 self.assertEqual(expected, got,
1135 "Incorrectly rounded str->float conversion for "
1136 "{}: expected {}, got {}".format(s, expected, got))
1137
1138 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
1139 "applies only when using short float repr style")
1140 def test_bug7632(self):
1141 # check a few particular values that gave incorrectly rounded
1142 # results with previous versions of dtoa.c
1143 test_strings = [
1144 '94393431193180696942841837085033647913224148539854e-358',
1145 '12579816049008305546974391768996369464963024663104e-357',
1146 '17489628565202117263145367596028389348922981857013e-357',
1147 '18487398785991994634182916638542680759613590482273e-357',
1148 '32002864200581033134358724675198044527469366773928e-358',
1149 '73608278998966969345824653500136787876436005957953e-358',
1150 '64774478836417299491718435234611299336288082136054e-358',
1151 '13704940134126574534878641876947980878824688451169e-357',
1152 '46697445774047060960624497964425416610480524760471e-358',
1153 ]
1154 for s in test_strings:
1155 self.check_string(s)
1156
Christian Heimes53876d92008-04-19 00:31:39 +00001157
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001158def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001159 support.run_unittest(
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +00001160 GeneralFloatCases,
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001161 FormatFunctionsTestCase,
1162 UnknownFormatTestCase,
Eric Smith8c663262007-08-25 02:26:07 +00001163 IEEEFormatTestCase,
Christian Heimes827b35c2007-12-10 22:19:17 +00001164 FormatTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +00001165 ReprTestCase,
Mark Dickinsone6a076d2009-04-18 11:48:33 +00001166 RoundTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +00001167 InfNanTest,
Mark Dickinson65fe25e2008-07-16 11:30:51 +00001168 HexFloatTestCase,
Mark Dickinson46672512010-01-12 23:09:26 +00001169 StrtodTestCase,
Christian Heimesb76922a2007-12-11 01:06:40 +00001170 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001171
1172if __name__ == '__main__':
1173 test_main()