blob: b4897c98a9be42b962401a7051bdf22f9df76de2 [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
124 # it still has to accept the normal python syntac
125 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
243
244
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000245class FormatFunctionsTestCase(unittest.TestCase):
246
247 def setUp(self):
248 self.save_formats = {'double':float.__getformat__('double'),
249 'float':float.__getformat__('float')}
250
251 def tearDown(self):
252 float.__setformat__('double', self.save_formats['double'])
253 float.__setformat__('float', self.save_formats['float'])
254
255 def test_getformat(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000256 self.assertTrue(float.__getformat__('double') in
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000257 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
Georg Brandlab91fde2009-08-13 08:51:18 +0000258 self.assertTrue(float.__getformat__('float') in
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000259 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
260 self.assertRaises(ValueError, float.__getformat__, 'chicken')
261 self.assertRaises(TypeError, float.__getformat__, 1)
262
263 def test_setformat(self):
264 for t in 'double', 'float':
265 float.__setformat__(t, 'unknown')
266 if self.save_formats[t] == 'IEEE, big-endian':
267 self.assertRaises(ValueError, float.__setformat__,
268 t, 'IEEE, little-endian')
269 elif self.save_formats[t] == 'IEEE, little-endian':
270 self.assertRaises(ValueError, float.__setformat__,
271 t, 'IEEE, big-endian')
272 else:
273 self.assertRaises(ValueError, float.__setformat__,
274 t, 'IEEE, big-endian')
275 self.assertRaises(ValueError, float.__setformat__,
276 t, 'IEEE, little-endian')
277 self.assertRaises(ValueError, float.__setformat__,
278 t, 'chicken')
279 self.assertRaises(ValueError, float.__setformat__,
280 'chicken', 'unknown')
281
Guido van Rossum2be161d2007-05-15 20:43:51 +0000282BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000283LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000284BE_DOUBLE_NAN = b'\x7f\xf8\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000285LE_DOUBLE_NAN = bytes(reversed(BE_DOUBLE_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000286
Guido van Rossum2be161d2007-05-15 20:43:51 +0000287BE_FLOAT_INF = b'\x7f\x80\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000288LE_FLOAT_INF = bytes(reversed(BE_FLOAT_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000289BE_FLOAT_NAN = b'\x7f\xc0\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000290LE_FLOAT_NAN = bytes(reversed(BE_FLOAT_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000291
292# on non-IEEE platforms, attempting to unpack a bit pattern
293# representing an infinity or a NaN should raise an exception.
294
295class UnknownFormatTestCase(unittest.TestCase):
296 def setUp(self):
297 self.save_formats = {'double':float.__getformat__('double'),
298 'float':float.__getformat__('float')}
299 float.__setformat__('double', 'unknown')
300 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000301
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000302 def tearDown(self):
303 float.__setformat__('double', self.save_formats['double'])
304 float.__setformat__('float', self.save_formats['float'])
305
306 def test_double_specials_dont_unpack(self):
307 for fmt, data in [('>d', BE_DOUBLE_INF),
308 ('>d', BE_DOUBLE_NAN),
309 ('<d', LE_DOUBLE_INF),
310 ('<d', LE_DOUBLE_NAN)]:
311 self.assertRaises(ValueError, struct.unpack, fmt, data)
312
313 def test_float_specials_dont_unpack(self):
314 for fmt, data in [('>f', BE_FLOAT_INF),
315 ('>f', BE_FLOAT_NAN),
316 ('<f', LE_FLOAT_INF),
317 ('<f', LE_FLOAT_NAN)]:
318 self.assertRaises(ValueError, struct.unpack, fmt, data)
319
320
321# on an IEEE platform, all we guarantee is that bit patterns
322# representing infinities or NaNs do not raise an exception; all else
323# is accident (today).
Guido van Rossum04110fb2007-08-24 16:32:05 +0000324# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000325
326class IEEEFormatTestCase(unittest.TestCase):
327 if float.__getformat__("double").startswith("IEEE"):
328 def test_double_specials_do_unpack(self):
329 for fmt, data in [('>d', BE_DOUBLE_INF),
330 ('>d', BE_DOUBLE_NAN),
331 ('<d', LE_DOUBLE_INF),
332 ('<d', LE_DOUBLE_NAN)]:
333 struct.unpack(fmt, data)
334
335 if float.__getformat__("float").startswith("IEEE"):
336 def test_float_specials_do_unpack(self):
337 for fmt, data in [('>f', BE_FLOAT_INF),
338 ('>f', BE_FLOAT_NAN),
339 ('<f', LE_FLOAT_INF),
340 ('<f', LE_FLOAT_NAN)]:
341 struct.unpack(fmt, data)
342
Guido van Rossum04110fb2007-08-24 16:32:05 +0000343 if float.__getformat__("double").startswith("IEEE"):
344 def test_negative_zero(self):
345 import math
346 def pos_pos():
347 return 0.0, math.atan2(0.0, -1)
348 def pos_neg():
349 return 0.0, math.atan2(-0.0, -1)
350 def neg_pos():
351 return -0.0, math.atan2(0.0, -1)
352 def neg_neg():
353 return -0.0, math.atan2(-0.0, -1)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000354 self.assertEqual(pos_pos(), neg_pos())
355 self.assertEqual(pos_neg(), neg_neg())
Guido van Rossum04110fb2007-08-24 16:32:05 +0000356
Eric Smith8c663262007-08-25 02:26:07 +0000357class FormatTestCase(unittest.TestCase):
Eric Smith11fe3e02007-08-31 01:33:06 +0000358 def test_format(self):
Eric Smith8c663262007-08-25 02:26:07 +0000359 # these should be rewritten to use both format(x, spec) and
360 # x.__format__(spec)
361
362 self.assertEqual(format(0.0, 'f'), '0.000000')
363
364 # the default is 'g', except for empty format spec
365 self.assertEqual(format(0.0, ''), '0.0')
366 self.assertEqual(format(0.01, ''), '0.01')
367 self.assertEqual(format(0.01, 'g'), '0.01')
368
Eric Smith63376222009-05-05 14:04:18 +0000369 # empty presentation type should format in the same way as str
370 # (issue 5920)
371 x = 100/7.
372 self.assertEqual(format(x, ''), str(x))
373 self.assertEqual(format(x, '-'), str(x))
374 self.assertEqual(format(x, '>'), str(x))
375 self.assertEqual(format(x, '2'), str(x))
Eric Smith8c663262007-08-25 02:26:07 +0000376
377 self.assertEqual(format(1.0, 'f'), '1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000378
379 self.assertEqual(format(-1.0, 'f'), '-1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000380
381 self.assertEqual(format( 1.0, ' f'), ' 1.000000')
382 self.assertEqual(format(-1.0, ' f'), '-1.000000')
383 self.assertEqual(format( 1.0, '+f'), '+1.000000')
384 self.assertEqual(format(-1.0, '+f'), '-1.000000')
385
386 # % formatting
387 self.assertEqual(format(-1.0, '%'), '-100.000000%')
388
389 # conversion to string should fail
390 self.assertRaises(ValueError, format, 3.0, "s")
391
Eric Smith7b69c6c2008-01-27 21:07:59 +0000392 # other format specifiers shouldn't work on floats,
393 # in particular int specifiers
394 for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
395 [chr(x) for x in range(ord('A'), ord('Z')+1)]):
396 if not format_spec in 'eEfFgGn%':
397 self.assertRaises(ValueError, format, 0.0, format_spec)
398 self.assertRaises(ValueError, format, 1.0, format_spec)
399 self.assertRaises(ValueError, format, -1.0, format_spec)
400 self.assertRaises(ValueError, format, 1e100, format_spec)
401 self.assertRaises(ValueError, format, -1e100, format_spec)
402 self.assertRaises(ValueError, format, 1e-100, format_spec)
403 self.assertRaises(ValueError, format, -1e-100, format_spec)
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000404
Eric Smith741191f2009-05-06 13:08:15 +0000405 # issue 3382
406 self.assertEqual(format(NAN, 'f'), 'nan')
407 self.assertEqual(format(NAN, 'F'), 'NAN')
408 self.assertEqual(format(INF, 'f'), 'inf')
409 self.assertEqual(format(INF, 'F'), 'INF')
410
Eric Smith0923d1d2009-04-16 20:16:10 +0000411 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
412 "test requires IEEE 754 doubles")
413 def test_format_testfile(self):
Brian Curtina813a632010-10-31 00:05:24 +0000414 with open(format_testfile) as testfile:
415 for line in testfile:
416 if line.startswith('--'):
417 continue
418 line = line.strip()
419 if not line:
420 continue
Eric Smith0923d1d2009-04-16 20:16:10 +0000421
Brian Curtina813a632010-10-31 00:05:24 +0000422 lhs, rhs = map(str.strip, line.split('->'))
423 fmt, arg = lhs.split()
424 self.assertEqual(fmt % float(arg), rhs)
425 self.assertEqual(fmt % -float(arg), '-' + rhs)
Eric Smith0923d1d2009-04-16 20:16:10 +0000426
Mark Dickinsond3ca5572009-04-29 18:47:07 +0000427 def test_issue5864(self):
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000428 self.assertEqual(format(123.456, '.4'), '123.5')
429 self.assertEqual(format(1234.56, '.4'), '1.235e+03')
430 self.assertEqual(format(12345.6, '.4'), '1.235e+04')
Mark Dickinsond3ca5572009-04-29 18:47:07 +0000431
Mark Dickinson7efad9e2009-04-17 20:59:58 +0000432class ReprTestCase(unittest.TestCase):
433 def test_repr(self):
434 floats_file = open(os.path.join(os.path.split(__file__)[0],
435 'floating_points.txt'))
436 for line in floats_file:
437 line = line.strip()
438 if not line or line.startswith('#'):
439 continue
440 v = eval(line)
441 self.assertEqual(v, eval(repr(v)))
442 floats_file.close()
443
Eric Smith0923d1d2009-04-16 20:16:10 +0000444 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
445 "applies only when using short float repr style")
446 def test_short_repr(self):
447 # test short float repr introduced in Python 3.1. One aspect
448 # of this repr is that we get some degree of str -> float ->
449 # str roundtripping. In particular, for any numeric string
450 # containing 15 or fewer significant digits, those exact same
451 # digits (modulo trailing zeros) should appear in the output.
452 # No more repr(0.03) -> "0.029999999999999999"!
453
454 test_strings = [
455 # output always includes *either* a decimal point and at
456 # least one digit after that point, or an exponent.
457 '0.0',
458 '1.0',
459 '0.01',
460 '0.02',
461 '0.03',
462 '0.04',
463 '0.05',
464 '1.23456789',
465 '10.0',
466 '100.0',
467 # values >= 1e16 get an exponent...
468 '1000000000000000.0',
469 '9999999999999990.0',
470 '1e+16',
471 '1e+17',
472 # ... and so do values < 1e-4
473 '0.001',
474 '0.001001',
475 '0.00010000000000001',
476 '0.0001',
477 '9.999999999999e-05',
478 '1e-05',
479 # values designed to provoke failure if the FPU rounding
480 # precision isn't set correctly
481 '8.72293771110361e+25',
482 '7.47005307342313e+26',
483 '2.86438000439698e+28',
484 '8.89142905246179e+28',
485 '3.08578087079232e+35',
486 ]
487
488 for s in test_strings:
489 negs = '-'+s
490 self.assertEqual(s, repr(float(s)))
491 self.assertEqual(negs, repr(float(negs)))
492
Mark Dickinsone6a076d2009-04-18 11:48:33 +0000493class RoundTestCase(unittest.TestCase):
494 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
495 "test requires IEEE 754 doubles")
496 def test_inf_nan(self):
497 self.assertRaises(OverflowError, round, INF)
498 self.assertRaises(OverflowError, round, -INF)
499 self.assertRaises(ValueError, round, NAN)
Mark Dickinsonae31a7c2009-11-24 11:00:21 +0000500 self.assertRaises(TypeError, round, INF, 0.0)
501 self.assertRaises(TypeError, round, -INF, 1.0)
502 self.assertRaises(TypeError, round, NAN, "ceci n'est pas un integer")
503 self.assertRaises(TypeError, round, -0.0, 1j)
Mark Dickinsone6a076d2009-04-18 11:48:33 +0000504
505 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
506 "test requires IEEE 754 doubles")
507 def test_large_n(self):
508 for n in [324, 325, 400, 2**31-1, 2**31, 2**32, 2**100]:
509 self.assertEqual(round(123.456, n), 123.456)
510 self.assertEqual(round(-123.456, n), -123.456)
511 self.assertEqual(round(1e300, n), 1e300)
512 self.assertEqual(round(1e-320, n), 1e-320)
513 self.assertEqual(round(1e150, 300), 1e150)
514 self.assertEqual(round(1e300, 307), 1e300)
515 self.assertEqual(round(-3.1415, 308), -3.1415)
516 self.assertEqual(round(1e150, 309), 1e150)
517 self.assertEqual(round(1.4e-315, 315), 1e-315)
518
519 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
520 "test requires IEEE 754 doubles")
521 def test_small_n(self):
522 for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]:
523 self.assertEqual(round(123.456, n), 0.0)
524 self.assertEqual(round(-123.456, n), -0.0)
525 self.assertEqual(round(1e300, n), 0.0)
526 self.assertEqual(round(1e-320, n), 0.0)
527
528 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
529 "test requires IEEE 754 doubles")
530 def test_overflow(self):
531 self.assertRaises(OverflowError, round, 1.6e308, -308)
532 self.assertRaises(OverflowError, round, -1.7e308, -308)
533
534 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
535 "applies only when using short float repr style")
536 def test_previous_round_bugs(self):
537 # particular cases that have occurred in bug reports
538 self.assertEqual(round(562949953421312.5, 1),
539 562949953421312.5)
540 self.assertEqual(round(56294995342131.5, 3),
541 56294995342131.5)
542 # round-half-even
543 self.assertEqual(round(25.0, -1), 20.0)
544 self.assertEqual(round(35.0, -1), 40.0)
545 self.assertEqual(round(45.0, -1), 40.0)
546 self.assertEqual(round(55.0, -1), 60.0)
547 self.assertEqual(round(65.0, -1), 60.0)
548 self.assertEqual(round(75.0, -1), 80.0)
549 self.assertEqual(round(85.0, -1), 80.0)
550 self.assertEqual(round(95.0, -1), 100.0)
551
552 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
553 "applies only when using short float repr style")
554 def test_matches_float_format(self):
555 # round should give the same results as float formatting
556 for i in range(500):
557 x = i/1000.
558 self.assertEqual(float(format(x, '.0f')), round(x, 0))
559 self.assertEqual(float(format(x, '.1f')), round(x, 1))
560 self.assertEqual(float(format(x, '.2f')), round(x, 2))
561 self.assertEqual(float(format(x, '.3f')), round(x, 3))
562
563 for i in range(5, 5000, 10):
564 x = i/1000.
565 self.assertEqual(float(format(x, '.0f')), round(x, 0))
566 self.assertEqual(float(format(x, '.1f')), round(x, 1))
567 self.assertEqual(float(format(x, '.2f')), round(x, 2))
568 self.assertEqual(float(format(x, '.3f')), round(x, 3))
569
570 for i in range(500):
571 x = random.random()
572 self.assertEqual(float(format(x, '.0f')), round(x, 0))
573 self.assertEqual(float(format(x, '.1f')), round(x, 1))
574 self.assertEqual(float(format(x, '.2f')), round(x, 2))
575 self.assertEqual(float(format(x, '.3f')), round(x, 3))
576
577
578
Christian Heimes99170a52007-12-19 02:07:34 +0000579# Beginning with Python 2.6 float has cross platform compatible
Georg Brandl2ee470f2008-07-16 12:55:28 +0000580# ways to create and represent inf and nan
Christian Heimes99170a52007-12-19 02:07:34 +0000581class InfNanTest(unittest.TestCase):
582 def test_inf_from_str(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000583 self.assertTrue(isinf(float("inf")))
584 self.assertTrue(isinf(float("+inf")))
585 self.assertTrue(isinf(float("-inf")))
586 self.assertTrue(isinf(float("infinity")))
587 self.assertTrue(isinf(float("+infinity")))
588 self.assertTrue(isinf(float("-infinity")))
Christian Heimes99170a52007-12-19 02:07:34 +0000589
590 self.assertEqual(repr(float("inf")), "inf")
591 self.assertEqual(repr(float("+inf")), "inf")
592 self.assertEqual(repr(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000593 self.assertEqual(repr(float("infinity")), "inf")
594 self.assertEqual(repr(float("+infinity")), "inf")
595 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000596
597 self.assertEqual(repr(float("INF")), "inf")
598 self.assertEqual(repr(float("+Inf")), "inf")
599 self.assertEqual(repr(float("-iNF")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000600 self.assertEqual(repr(float("Infinity")), "inf")
601 self.assertEqual(repr(float("+iNfInItY")), "inf")
602 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000603
604 self.assertEqual(str(float("inf")), "inf")
605 self.assertEqual(str(float("+inf")), "inf")
606 self.assertEqual(str(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000607 self.assertEqual(str(float("infinity")), "inf")
608 self.assertEqual(str(float("+infinity")), "inf")
609 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000610
611 self.assertRaises(ValueError, float, "info")
612 self.assertRaises(ValueError, float, "+info")
613 self.assertRaises(ValueError, float, "-info")
614 self.assertRaises(ValueError, float, "in")
615 self.assertRaises(ValueError, float, "+in")
616 self.assertRaises(ValueError, float, "-in")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000617 self.assertRaises(ValueError, float, "infinit")
618 self.assertRaises(ValueError, float, "+Infin")
619 self.assertRaises(ValueError, float, "-INFI")
620 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes99170a52007-12-19 02:07:34 +0000621
Mark Dickinsonbd16edd2009-05-20 22:05:25 +0000622 self.assertRaises(ValueError, float, "++Inf")
623 self.assertRaises(ValueError, float, "-+inf")
624 self.assertRaises(ValueError, float, "+-infinity")
625 self.assertRaises(ValueError, float, "--Infinity")
626
Christian Heimes99170a52007-12-19 02:07:34 +0000627 def test_inf_as_str(self):
628 self.assertEqual(repr(1e300 * 1e300), "inf")
629 self.assertEqual(repr(-1e300 * 1e300), "-inf")
630
631 self.assertEqual(str(1e300 * 1e300), "inf")
632 self.assertEqual(str(-1e300 * 1e300), "-inf")
633
634 def test_nan_from_str(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000635 self.assertTrue(isnan(float("nan")))
636 self.assertTrue(isnan(float("+nan")))
637 self.assertTrue(isnan(float("-nan")))
Christian Heimes99170a52007-12-19 02:07:34 +0000638
639 self.assertEqual(repr(float("nan")), "nan")
640 self.assertEqual(repr(float("+nan")), "nan")
641 self.assertEqual(repr(float("-nan")), "nan")
642
643 self.assertEqual(repr(float("NAN")), "nan")
644 self.assertEqual(repr(float("+NAn")), "nan")
645 self.assertEqual(repr(float("-NaN")), "nan")
646
647 self.assertEqual(str(float("nan")), "nan")
648 self.assertEqual(str(float("+nan")), "nan")
649 self.assertEqual(str(float("-nan")), "nan")
650
651 self.assertRaises(ValueError, float, "nana")
652 self.assertRaises(ValueError, float, "+nana")
653 self.assertRaises(ValueError, float, "-nana")
654 self.assertRaises(ValueError, float, "na")
655 self.assertRaises(ValueError, float, "+na")
656 self.assertRaises(ValueError, float, "-na")
657
Mark Dickinsonbd16edd2009-05-20 22:05:25 +0000658 self.assertRaises(ValueError, float, "++nan")
659 self.assertRaises(ValueError, float, "-+NAN")
660 self.assertRaises(ValueError, float, "+-NaN")
661 self.assertRaises(ValueError, float, "--nAn")
662
Christian Heimes99170a52007-12-19 02:07:34 +0000663 def test_nan_as_str(self):
664 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
665 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
666
667 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
668 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes827b35c2007-12-10 22:19:17 +0000669
Christian Heimes53876d92008-04-19 00:31:39 +0000670 def notest_float_nan(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000671 self.assertTrue(NAN.is_nan())
672 self.assertFalse(INF.is_nan())
673 self.assertFalse((0.).is_nan())
Christian Heimes53876d92008-04-19 00:31:39 +0000674
675 def notest_float_inf(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000676 self.assertTrue(INF.is_inf())
677 self.assertFalse(NAN.is_inf())
678 self.assertFalse((0.).is_inf())
Christian Heimes53876d92008-04-19 00:31:39 +0000679
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000680fromHex = float.fromhex
681toHex = float.hex
682class HexFloatTestCase(unittest.TestCase):
683 MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
684 MIN = fromHex('0x1p-1022') # min normal
685 TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
686 EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
687
688 def identical(self, x, y):
689 # check that floats x and y are identical, or that both
690 # are NaNs
691 if isnan(x) or isnan(y):
692 if isnan(x) == isnan(y):
693 return
694 elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
695 return
696 self.fail('%r not identical to %r' % (x, y))
697
698 def test_ends(self):
Mark Dickinson38bbc482008-07-16 11:32:23 +0000699 self.identical(self.MIN, ldexp(1.0, -1022))
700 self.identical(self.TINY, ldexp(1.0, -1074))
701 self.identical(self.EPS, ldexp(1.0, -52))
702 self.identical(self.MAX, 2.*(ldexp(1.0, 1023) - ldexp(1.0, 970)))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000703
704 def test_invalid_inputs(self):
705 invalid_inputs = [
706 'infi', # misspelt infinities and nans
707 '-Infinit',
708 '++inf',
709 '-+Inf',
710 '--nan',
711 '+-NaN',
712 'snan',
713 'NaNs',
714 'nna',
Mark Dickinsond1ec8b22009-05-11 15:45:15 +0000715 'an',
716 'nf',
717 'nfinity',
718 'inity',
719 'iinity',
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000720 '0xnan',
721 '',
722 ' ',
723 'x1.0p0',
724 '0xX1.0p0',
725 '+ 0x1.0p0', # internal whitespace
726 '- 0x1.0p0',
727 '0 x1.0p0',
728 '0x 1.0p0',
729 '0x1 2.0p0',
730 '+0x1 .0p0',
731 '0x1. 0p0',
732 '-0x1.0 1p0',
733 '-0x1.0 p0',
734 '+0x1.0p +0',
735 '0x1.0p -0',
736 '0x1.0p 0',
737 '+0x1.0p+ 0',
738 '-0x1.0p- 0',
739 '++0x1.0p-0', # double signs
740 '--0x1.0p0',
741 '+-0x1.0p+0',
742 '-+0x1.0p0',
743 '0x1.0p++0',
744 '+0x1.0p+-0',
745 '-0x1.0p-+0',
746 '0x1.0p--0',
747 '0x1.0.p0',
748 '0x.p0', # no hex digits before or after point
749 '0x1,p0', # wrong decimal point character
750 '0x1pa',
751 '0x1p\uff10', # fullwidth Unicode digits
752 '\uff10x1p0',
753 '0x\uff11p0',
754 '0x1.\uff10p0',
755 '0x1p0 \n 0x2p0',
756 '0x1p0\0 0x1p0', # embedded null byte is not end of string
757 ]
758 for x in invalid_inputs:
Mark Dickinson589b7952008-08-21 20:05:56 +0000759 try:
760 result = fromHex(x)
761 except ValueError:
762 pass
763 else:
764 self.fail('Expected float.fromhex(%r) to raise ValueError; '
765 'got %r instead' % (x, result))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000766
767
Mark Dickinsond1ec8b22009-05-11 15:45:15 +0000768 def test_whitespace(self):
769 value_pairs = [
770 ('inf', INF),
771 ('-Infinity', -INF),
772 ('nan', NAN),
773 ('1.0', 1.0),
774 ('-0x.2', -0.125),
775 ('-0.0', -0.0)
776 ]
777 whitespace = [
778 '',
779 ' ',
780 '\t',
781 '\n',
782 '\n \t',
783 '\f',
784 '\v',
785 '\r'
786 ]
787 for inp, expected in value_pairs:
788 for lead in whitespace:
789 for trail in whitespace:
790 got = fromHex(lead + inp + trail)
791 self.identical(got, expected)
792
793
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000794 def test_from_hex(self):
795 MIN = self.MIN;
796 MAX = self.MAX;
797 TINY = self.TINY;
798 EPS = self.EPS;
799
800 # two spellings of infinity, with optional signs; case-insensitive
801 self.identical(fromHex('inf'), INF)
802 self.identical(fromHex('+Inf'), INF)
803 self.identical(fromHex('-INF'), -INF)
804 self.identical(fromHex('iNf'), INF)
805 self.identical(fromHex('Infinity'), INF)
806 self.identical(fromHex('+INFINITY'), INF)
807 self.identical(fromHex('-infinity'), -INF)
808 self.identical(fromHex('-iNFiNitY'), -INF)
809
810 # nans with optional sign; case insensitive
811 self.identical(fromHex('nan'), NAN)
812 self.identical(fromHex('+NaN'), NAN)
813 self.identical(fromHex('-NaN'), NAN)
814 self.identical(fromHex('-nAN'), NAN)
815
816 # variations in input format
817 self.identical(fromHex('1'), 1.0)
818 self.identical(fromHex('+1'), 1.0)
819 self.identical(fromHex('1.'), 1.0)
820 self.identical(fromHex('1.0'), 1.0)
821 self.identical(fromHex('1.0p0'), 1.0)
822 self.identical(fromHex('01'), 1.0)
823 self.identical(fromHex('01.'), 1.0)
824 self.identical(fromHex('0x1'), 1.0)
825 self.identical(fromHex('0x1.'), 1.0)
826 self.identical(fromHex('0x1.0'), 1.0)
827 self.identical(fromHex('+0x1.0'), 1.0)
828 self.identical(fromHex('0x1p0'), 1.0)
829 self.identical(fromHex('0X1p0'), 1.0)
830 self.identical(fromHex('0X1P0'), 1.0)
831 self.identical(fromHex('0x1P0'), 1.0)
832 self.identical(fromHex('0x1.p0'), 1.0)
833 self.identical(fromHex('0x1.0p0'), 1.0)
834 self.identical(fromHex('0x.1p4'), 1.0)
835 self.identical(fromHex('0x.1p04'), 1.0)
836 self.identical(fromHex('0x.1p004'), 1.0)
837 self.identical(fromHex('0x1p+0'), 1.0)
838 self.identical(fromHex('0x1P-0'), 1.0)
839 self.identical(fromHex('+0x1p0'), 1.0)
840 self.identical(fromHex('0x01p0'), 1.0)
841 self.identical(fromHex('0x1p00'), 1.0)
842 self.identical(fromHex(' 0x1p0 '), 1.0)
843 self.identical(fromHex('\n 0x1p0'), 1.0)
844 self.identical(fromHex('0x1p0 \t'), 1.0)
845 self.identical(fromHex('0xap0'), 10.0)
846 self.identical(fromHex('0xAp0'), 10.0)
847 self.identical(fromHex('0xaP0'), 10.0)
848 self.identical(fromHex('0xAP0'), 10.0)
849 self.identical(fromHex('0xbep0'), 190.0)
850 self.identical(fromHex('0xBep0'), 190.0)
851 self.identical(fromHex('0xbEp0'), 190.0)
852 self.identical(fromHex('0XBE0P-4'), 190.0)
853 self.identical(fromHex('0xBEp0'), 190.0)
854 self.identical(fromHex('0xB.Ep4'), 190.0)
855 self.identical(fromHex('0x.BEp8'), 190.0)
856 self.identical(fromHex('0x.0BEp12'), 190.0)
857
858 # moving the point around
859 pi = fromHex('0x1.921fb54442d18p1')
860 self.identical(fromHex('0x.006487ed5110b46p11'), pi)
861 self.identical(fromHex('0x.00c90fdaa22168cp10'), pi)
862 self.identical(fromHex('0x.01921fb54442d18p9'), pi)
863 self.identical(fromHex('0x.03243f6a8885a3p8'), pi)
864 self.identical(fromHex('0x.06487ed5110b46p7'), pi)
865 self.identical(fromHex('0x.0c90fdaa22168cp6'), pi)
866 self.identical(fromHex('0x.1921fb54442d18p5'), pi)
867 self.identical(fromHex('0x.3243f6a8885a3p4'), pi)
868 self.identical(fromHex('0x.6487ed5110b46p3'), pi)
869 self.identical(fromHex('0x.c90fdaa22168cp2'), pi)
870 self.identical(fromHex('0x1.921fb54442d18p1'), pi)
871 self.identical(fromHex('0x3.243f6a8885a3p0'), pi)
872 self.identical(fromHex('0x6.487ed5110b46p-1'), pi)
873 self.identical(fromHex('0xc.90fdaa22168cp-2'), pi)
874 self.identical(fromHex('0x19.21fb54442d18p-3'), pi)
875 self.identical(fromHex('0x32.43f6a8885a3p-4'), pi)
876 self.identical(fromHex('0x64.87ed5110b46p-5'), pi)
877 self.identical(fromHex('0xc9.0fdaa22168cp-6'), pi)
878 self.identical(fromHex('0x192.1fb54442d18p-7'), pi)
879 self.identical(fromHex('0x324.3f6a8885a3p-8'), pi)
880 self.identical(fromHex('0x648.7ed5110b46p-9'), pi)
881 self.identical(fromHex('0xc90.fdaa22168cp-10'), pi)
882 self.identical(fromHex('0x1921.fb54442d18p-11'), pi)
883 # ...
884 self.identical(fromHex('0x1921fb54442d1.8p-47'), pi)
885 self.identical(fromHex('0x3243f6a8885a3p-48'), pi)
886 self.identical(fromHex('0x6487ed5110b46p-49'), pi)
887 self.identical(fromHex('0xc90fdaa22168cp-50'), pi)
888 self.identical(fromHex('0x1921fb54442d18p-51'), pi)
889 self.identical(fromHex('0x3243f6a8885a30p-52'), pi)
890 self.identical(fromHex('0x6487ed5110b460p-53'), pi)
891 self.identical(fromHex('0xc90fdaa22168c0p-54'), pi)
892 self.identical(fromHex('0x1921fb54442d180p-55'), pi)
893
894
895 # results that should overflow...
896 self.assertRaises(OverflowError, fromHex, '-0x1p1024')
897 self.assertRaises(OverflowError, fromHex, '0x1p+1025')
898 self.assertRaises(OverflowError, fromHex, '+0X1p1030')
899 self.assertRaises(OverflowError, fromHex, '-0x1p+1100')
900 self.assertRaises(OverflowError, fromHex, '0X1p123456789123456789')
901 self.assertRaises(OverflowError, fromHex, '+0X.8p+1025')
902 self.assertRaises(OverflowError, fromHex, '+0x0.8p1025')
903 self.assertRaises(OverflowError, fromHex, '-0x0.4p1026')
904 self.assertRaises(OverflowError, fromHex, '0X2p+1023')
905 self.assertRaises(OverflowError, fromHex, '0x2.p1023')
906 self.assertRaises(OverflowError, fromHex, '-0x2.0p+1023')
907 self.assertRaises(OverflowError, fromHex, '+0X4p+1022')
908 self.assertRaises(OverflowError, fromHex, '0x1.ffffffffffffffp+1023')
909 self.assertRaises(OverflowError, fromHex, '-0X1.fffffffffffff9p1023')
910 self.assertRaises(OverflowError, fromHex, '0X1.fffffffffffff8p1023')
911 self.assertRaises(OverflowError, fromHex, '+0x3.fffffffffffffp1022')
912 self.assertRaises(OverflowError, fromHex, '0x3fffffffffffffp+970')
913 self.assertRaises(OverflowError, fromHex, '0x10000000000000000p960')
914 self.assertRaises(OverflowError, fromHex, '-0Xffffffffffffffffp960')
915
916 # ...and those that round to +-max float
917 self.identical(fromHex('+0x1.fffffffffffffp+1023'), MAX)
918 self.identical(fromHex('-0X1.fffffffffffff7p1023'), -MAX)
919 self.identical(fromHex('0X1.fffffffffffff7fffffffffffffp1023'), MAX)
920
921 # zeros
922 self.identical(fromHex('0x0p0'), 0.0)
923 self.identical(fromHex('0x0p1000'), 0.0)
924 self.identical(fromHex('-0x0p1023'), -0.0)
925 self.identical(fromHex('0X0p1024'), 0.0)
926 self.identical(fromHex('-0x0p1025'), -0.0)
927 self.identical(fromHex('0X0p2000'), 0.0)
928 self.identical(fromHex('0x0p123456789123456789'), 0.0)
929 self.identical(fromHex('-0X0p-0'), -0.0)
930 self.identical(fromHex('-0X0p-1000'), -0.0)
931 self.identical(fromHex('0x0p-1023'), 0.0)
932 self.identical(fromHex('-0X0p-1024'), -0.0)
933 self.identical(fromHex('-0x0p-1025'), -0.0)
934 self.identical(fromHex('-0x0p-1072'), -0.0)
935 self.identical(fromHex('0X0p-1073'), 0.0)
936 self.identical(fromHex('-0x0p-1074'), -0.0)
937 self.identical(fromHex('0x0p-1075'), 0.0)
938 self.identical(fromHex('0X0p-1076'), 0.0)
939 self.identical(fromHex('-0X0p-2000'), -0.0)
940 self.identical(fromHex('-0x0p-123456789123456789'), -0.0)
941
942 # values that should underflow to 0
943 self.identical(fromHex('0X1p-1075'), 0.0)
944 self.identical(fromHex('-0X1p-1075'), -0.0)
945 self.identical(fromHex('-0x1p-123456789123456789'), -0.0)
946 self.identical(fromHex('0x1.00000000000000001p-1075'), TINY)
947 self.identical(fromHex('-0x1.1p-1075'), -TINY)
948 self.identical(fromHex('0x1.fffffffffffffffffp-1075'), TINY)
949
950 # check round-half-even is working correctly near 0 ...
951 self.identical(fromHex('0x1p-1076'), 0.0)
952 self.identical(fromHex('0X2p-1076'), 0.0)
953 self.identical(fromHex('0X3p-1076'), TINY)
954 self.identical(fromHex('0x4p-1076'), TINY)
955 self.identical(fromHex('0X5p-1076'), TINY)
956 self.identical(fromHex('0X6p-1076'), 2*TINY)
957 self.identical(fromHex('0x7p-1076'), 2*TINY)
958 self.identical(fromHex('0X8p-1076'), 2*TINY)
959 self.identical(fromHex('0X9p-1076'), 2*TINY)
960 self.identical(fromHex('0xap-1076'), 2*TINY)
961 self.identical(fromHex('0Xbp-1076'), 3*TINY)
962 self.identical(fromHex('0xcp-1076'), 3*TINY)
963 self.identical(fromHex('0Xdp-1076'), 3*TINY)
964 self.identical(fromHex('0Xep-1076'), 4*TINY)
965 self.identical(fromHex('0xfp-1076'), 4*TINY)
966 self.identical(fromHex('0x10p-1076'), 4*TINY)
967 self.identical(fromHex('-0x1p-1076'), -0.0)
968 self.identical(fromHex('-0X2p-1076'), -0.0)
969 self.identical(fromHex('-0x3p-1076'), -TINY)
970 self.identical(fromHex('-0X4p-1076'), -TINY)
971 self.identical(fromHex('-0x5p-1076'), -TINY)
972 self.identical(fromHex('-0x6p-1076'), -2*TINY)
973 self.identical(fromHex('-0X7p-1076'), -2*TINY)
974 self.identical(fromHex('-0X8p-1076'), -2*TINY)
975 self.identical(fromHex('-0X9p-1076'), -2*TINY)
976 self.identical(fromHex('-0Xap-1076'), -2*TINY)
977 self.identical(fromHex('-0xbp-1076'), -3*TINY)
978 self.identical(fromHex('-0xcp-1076'), -3*TINY)
979 self.identical(fromHex('-0Xdp-1076'), -3*TINY)
980 self.identical(fromHex('-0xep-1076'), -4*TINY)
981 self.identical(fromHex('-0Xfp-1076'), -4*TINY)
982 self.identical(fromHex('-0X10p-1076'), -4*TINY)
983
984 # ... and near MIN ...
985 self.identical(fromHex('0x0.ffffffffffffd6p-1022'), MIN-3*TINY)
986 self.identical(fromHex('0x0.ffffffffffffd8p-1022'), MIN-2*TINY)
987 self.identical(fromHex('0x0.ffffffffffffdap-1022'), MIN-2*TINY)
988 self.identical(fromHex('0x0.ffffffffffffdcp-1022'), MIN-2*TINY)
989 self.identical(fromHex('0x0.ffffffffffffdep-1022'), MIN-2*TINY)
990 self.identical(fromHex('0x0.ffffffffffffe0p-1022'), MIN-2*TINY)
991 self.identical(fromHex('0x0.ffffffffffffe2p-1022'), MIN-2*TINY)
992 self.identical(fromHex('0x0.ffffffffffffe4p-1022'), MIN-2*TINY)
993 self.identical(fromHex('0x0.ffffffffffffe6p-1022'), MIN-2*TINY)
994 self.identical(fromHex('0x0.ffffffffffffe8p-1022'), MIN-2*TINY)
995 self.identical(fromHex('0x0.ffffffffffffeap-1022'), MIN-TINY)
996 self.identical(fromHex('0x0.ffffffffffffecp-1022'), MIN-TINY)
997 self.identical(fromHex('0x0.ffffffffffffeep-1022'), MIN-TINY)
998 self.identical(fromHex('0x0.fffffffffffff0p-1022'), MIN-TINY)
999 self.identical(fromHex('0x0.fffffffffffff2p-1022'), MIN-TINY)
1000 self.identical(fromHex('0x0.fffffffffffff4p-1022'), MIN-TINY)
1001 self.identical(fromHex('0x0.fffffffffffff6p-1022'), MIN-TINY)
1002 self.identical(fromHex('0x0.fffffffffffff8p-1022'), MIN)
1003 self.identical(fromHex('0x0.fffffffffffffap-1022'), MIN)
1004 self.identical(fromHex('0x0.fffffffffffffcp-1022'), MIN)
1005 self.identical(fromHex('0x0.fffffffffffffep-1022'), MIN)
1006 self.identical(fromHex('0x1.00000000000000p-1022'), MIN)
1007 self.identical(fromHex('0x1.00000000000002p-1022'), MIN)
1008 self.identical(fromHex('0x1.00000000000004p-1022'), MIN)
1009 self.identical(fromHex('0x1.00000000000006p-1022'), MIN)
1010 self.identical(fromHex('0x1.00000000000008p-1022'), MIN)
1011 self.identical(fromHex('0x1.0000000000000ap-1022'), MIN+TINY)
1012 self.identical(fromHex('0x1.0000000000000cp-1022'), MIN+TINY)
1013 self.identical(fromHex('0x1.0000000000000ep-1022'), MIN+TINY)
1014 self.identical(fromHex('0x1.00000000000010p-1022'), MIN+TINY)
1015 self.identical(fromHex('0x1.00000000000012p-1022'), MIN+TINY)
1016 self.identical(fromHex('0x1.00000000000014p-1022'), MIN+TINY)
1017 self.identical(fromHex('0x1.00000000000016p-1022'), MIN+TINY)
1018 self.identical(fromHex('0x1.00000000000018p-1022'), MIN+2*TINY)
1019
1020 # ... and near 1.0.
1021 self.identical(fromHex('0x0.fffffffffffff0p0'), 1.0-EPS)
1022 self.identical(fromHex('0x0.fffffffffffff1p0'), 1.0-EPS)
1023 self.identical(fromHex('0X0.fffffffffffff2p0'), 1.0-EPS)
1024 self.identical(fromHex('0x0.fffffffffffff3p0'), 1.0-EPS)
1025 self.identical(fromHex('0X0.fffffffffffff4p0'), 1.0-EPS)
1026 self.identical(fromHex('0X0.fffffffffffff5p0'), 1.0-EPS/2)
1027 self.identical(fromHex('0X0.fffffffffffff6p0'), 1.0-EPS/2)
1028 self.identical(fromHex('0x0.fffffffffffff7p0'), 1.0-EPS/2)
1029 self.identical(fromHex('0x0.fffffffffffff8p0'), 1.0-EPS/2)
1030 self.identical(fromHex('0X0.fffffffffffff9p0'), 1.0-EPS/2)
1031 self.identical(fromHex('0X0.fffffffffffffap0'), 1.0-EPS/2)
1032 self.identical(fromHex('0x0.fffffffffffffbp0'), 1.0-EPS/2)
1033 self.identical(fromHex('0X0.fffffffffffffcp0'), 1.0)
1034 self.identical(fromHex('0x0.fffffffffffffdp0'), 1.0)
1035 self.identical(fromHex('0X0.fffffffffffffep0'), 1.0)
1036 self.identical(fromHex('0x0.ffffffffffffffp0'), 1.0)
1037 self.identical(fromHex('0X1.00000000000000p0'), 1.0)
1038 self.identical(fromHex('0X1.00000000000001p0'), 1.0)
1039 self.identical(fromHex('0x1.00000000000002p0'), 1.0)
1040 self.identical(fromHex('0X1.00000000000003p0'), 1.0)
1041 self.identical(fromHex('0x1.00000000000004p0'), 1.0)
1042 self.identical(fromHex('0X1.00000000000005p0'), 1.0)
1043 self.identical(fromHex('0X1.00000000000006p0'), 1.0)
1044 self.identical(fromHex('0X1.00000000000007p0'), 1.0)
1045 self.identical(fromHex('0x1.00000000000007ffffffffffffffffffffp0'),
1046 1.0)
1047 self.identical(fromHex('0x1.00000000000008p0'), 1.0)
1048 self.identical(fromHex('0x1.00000000000008000000000000000001p0'),
1049 1+EPS)
1050 self.identical(fromHex('0X1.00000000000009p0'), 1.0+EPS)
1051 self.identical(fromHex('0x1.0000000000000ap0'), 1.0+EPS)
1052 self.identical(fromHex('0x1.0000000000000bp0'), 1.0+EPS)
1053 self.identical(fromHex('0X1.0000000000000cp0'), 1.0+EPS)
1054 self.identical(fromHex('0x1.0000000000000dp0'), 1.0+EPS)
1055 self.identical(fromHex('0x1.0000000000000ep0'), 1.0+EPS)
1056 self.identical(fromHex('0X1.0000000000000fp0'), 1.0+EPS)
1057 self.identical(fromHex('0x1.00000000000010p0'), 1.0+EPS)
1058 self.identical(fromHex('0X1.00000000000011p0'), 1.0+EPS)
1059 self.identical(fromHex('0x1.00000000000012p0'), 1.0+EPS)
1060 self.identical(fromHex('0X1.00000000000013p0'), 1.0+EPS)
1061 self.identical(fromHex('0X1.00000000000014p0'), 1.0+EPS)
1062 self.identical(fromHex('0x1.00000000000015p0'), 1.0+EPS)
1063 self.identical(fromHex('0x1.00000000000016p0'), 1.0+EPS)
1064 self.identical(fromHex('0X1.00000000000017p0'), 1.0+EPS)
1065 self.identical(fromHex('0x1.00000000000017ffffffffffffffffffffp0'),
1066 1.0+EPS)
1067 self.identical(fromHex('0x1.00000000000018p0'), 1.0+2*EPS)
1068 self.identical(fromHex('0X1.00000000000018000000000000000001p0'),
1069 1.0+2*EPS)
1070 self.identical(fromHex('0x1.00000000000019p0'), 1.0+2*EPS)
1071 self.identical(fromHex('0X1.0000000000001ap0'), 1.0+2*EPS)
1072 self.identical(fromHex('0X1.0000000000001bp0'), 1.0+2*EPS)
1073 self.identical(fromHex('0x1.0000000000001cp0'), 1.0+2*EPS)
1074 self.identical(fromHex('0x1.0000000000001dp0'), 1.0+2*EPS)
1075 self.identical(fromHex('0x1.0000000000001ep0'), 1.0+2*EPS)
1076 self.identical(fromHex('0X1.0000000000001fp0'), 1.0+2*EPS)
1077 self.identical(fromHex('0x1.00000000000020p0'), 1.0+2*EPS)
1078
1079 def test_roundtrip(self):
1080 def roundtrip(x):
1081 return fromHex(toHex(x))
1082
1083 for x in [NAN, INF, self.MAX, self.MIN, self.MIN-self.TINY, self.TINY, 0.0]:
1084 self.identical(x, roundtrip(x))
1085 self.identical(-x, roundtrip(-x))
1086
1087 # fromHex(toHex(x)) should exactly recover x, for any non-NaN float x.
1088 import random
1089 for i in range(10000):
1090 e = random.randrange(-1200, 1200)
1091 m = random.random()
1092 s = random.choice([1.0, -1.0])
1093 try:
1094 x = s*ldexp(m, e)
1095 except OverflowError:
1096 pass
1097 else:
1098 self.identical(x, fromHex(toHex(x)))
1099
Mark Dickinson46672512010-01-12 23:09:26 +00001100class StrtodTestCase(unittest.TestCase):
1101 def check_string(self, s):
1102 expected = strtod(s)
1103 try:
1104 fs = float(s)
1105 except OverflowError:
1106 got = '-inf' if s[0] == '-' else 'inf'
1107 else:
1108 got = fs.hex()
1109 self.assertEqual(expected, got,
1110 "Incorrectly rounded str->float conversion for "
1111 "{}: expected {}, got {}".format(s, expected, got))
1112
1113 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
1114 "applies only when using short float repr style")
1115 def test_bug7632(self):
1116 # check a few particular values that gave incorrectly rounded
1117 # results with previous versions of dtoa.c
1118 test_strings = [
1119 '94393431193180696942841837085033647913224148539854e-358',
1120 '12579816049008305546974391768996369464963024663104e-357',
1121 '17489628565202117263145367596028389348922981857013e-357',
1122 '18487398785991994634182916638542680759613590482273e-357',
1123 '32002864200581033134358724675198044527469366773928e-358',
1124 '73608278998966969345824653500136787876436005957953e-358',
1125 '64774478836417299491718435234611299336288082136054e-358',
1126 '13704940134126574534878641876947980878824688451169e-357',
1127 '46697445774047060960624497964425416610480524760471e-358',
1128 ]
1129 for s in test_strings:
1130 self.check_string(s)
1131
Christian Heimes53876d92008-04-19 00:31:39 +00001132
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001133def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001134 support.run_unittest(
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +00001135 GeneralFloatCases,
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001136 FormatFunctionsTestCase,
1137 UnknownFormatTestCase,
Eric Smith8c663262007-08-25 02:26:07 +00001138 IEEEFormatTestCase,
Christian Heimes827b35c2007-12-10 22:19:17 +00001139 FormatTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +00001140 ReprTestCase,
Mark Dickinsone6a076d2009-04-18 11:48:33 +00001141 RoundTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +00001142 InfNanTest,
Mark Dickinson65fe25e2008-07-16 11:30:51 +00001143 HexFloatTestCase,
Mark Dickinson46672512010-01-12 23:09:26 +00001144 StrtodTestCase,
Christian Heimesb76922a2007-12-11 01:06:40 +00001145 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001146
1147if __name__ == '__main__':
1148 test_main()