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