blob: fa6fde32810a84bb2e89fcb8e8e063f1bcddc43f [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):
404 for line in open(format_testfile):
405 if line.startswith('--'):
406 continue
407 line = line.strip()
408 if not line:
409 continue
410
411 lhs, rhs = map(str.strip, line.split('->'))
412 fmt, arg = lhs.split()
413 self.assertEqual(fmt % float(arg), rhs)
414 self.assertEqual(fmt % -float(arg), '-' + rhs)
415
Mark Dickinsond3ca5572009-04-29 18:47:07 +0000416 def test_issue5864(self):
417 self.assertEquals(format(123.456, '.4'), '123.5')
418 self.assertEquals(format(1234.56, '.4'), '1.235e+03')
419 self.assertEquals(format(12345.6, '.4'), '1.235e+04')
420
Mark Dickinson7efad9e2009-04-17 20:59:58 +0000421class ReprTestCase(unittest.TestCase):
422 def test_repr(self):
423 floats_file = open(os.path.join(os.path.split(__file__)[0],
424 'floating_points.txt'))
425 for line in floats_file:
426 line = line.strip()
427 if not line or line.startswith('#'):
428 continue
429 v = eval(line)
430 self.assertEqual(v, eval(repr(v)))
431 floats_file.close()
432
Eric Smith0923d1d2009-04-16 20:16:10 +0000433 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
434 "applies only when using short float repr style")
435 def test_short_repr(self):
436 # test short float repr introduced in Python 3.1. One aspect
437 # of this repr is that we get some degree of str -> float ->
438 # str roundtripping. In particular, for any numeric string
439 # containing 15 or fewer significant digits, those exact same
440 # digits (modulo trailing zeros) should appear in the output.
441 # No more repr(0.03) -> "0.029999999999999999"!
442
443 test_strings = [
444 # output always includes *either* a decimal point and at
445 # least one digit after that point, or an exponent.
446 '0.0',
447 '1.0',
448 '0.01',
449 '0.02',
450 '0.03',
451 '0.04',
452 '0.05',
453 '1.23456789',
454 '10.0',
455 '100.0',
456 # values >= 1e16 get an exponent...
457 '1000000000000000.0',
458 '9999999999999990.0',
459 '1e+16',
460 '1e+17',
461 # ... and so do values < 1e-4
462 '0.001',
463 '0.001001',
464 '0.00010000000000001',
465 '0.0001',
466 '9.999999999999e-05',
467 '1e-05',
468 # values designed to provoke failure if the FPU rounding
469 # precision isn't set correctly
470 '8.72293771110361e+25',
471 '7.47005307342313e+26',
472 '2.86438000439698e+28',
473 '8.89142905246179e+28',
474 '3.08578087079232e+35',
475 ]
476
477 for s in test_strings:
478 negs = '-'+s
479 self.assertEqual(s, repr(float(s)))
480 self.assertEqual(negs, repr(float(negs)))
481
Mark Dickinsone6a076d2009-04-18 11:48:33 +0000482class RoundTestCase(unittest.TestCase):
483 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
484 "test requires IEEE 754 doubles")
485 def test_inf_nan(self):
486 self.assertRaises(OverflowError, round, INF)
487 self.assertRaises(OverflowError, round, -INF)
488 self.assertRaises(ValueError, round, NAN)
Mark Dickinsonae31a7c2009-11-24 11:00:21 +0000489 self.assertRaises(TypeError, round, INF, 0.0)
490 self.assertRaises(TypeError, round, -INF, 1.0)
491 self.assertRaises(TypeError, round, NAN, "ceci n'est pas un integer")
492 self.assertRaises(TypeError, round, -0.0, 1j)
Mark Dickinsone6a076d2009-04-18 11:48:33 +0000493
494 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
495 "test requires IEEE 754 doubles")
496 def test_large_n(self):
497 for n in [324, 325, 400, 2**31-1, 2**31, 2**32, 2**100]:
498 self.assertEqual(round(123.456, n), 123.456)
499 self.assertEqual(round(-123.456, n), -123.456)
500 self.assertEqual(round(1e300, n), 1e300)
501 self.assertEqual(round(1e-320, n), 1e-320)
502 self.assertEqual(round(1e150, 300), 1e150)
503 self.assertEqual(round(1e300, 307), 1e300)
504 self.assertEqual(round(-3.1415, 308), -3.1415)
505 self.assertEqual(round(1e150, 309), 1e150)
506 self.assertEqual(round(1.4e-315, 315), 1e-315)
507
508 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
509 "test requires IEEE 754 doubles")
510 def test_small_n(self):
511 for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]:
512 self.assertEqual(round(123.456, n), 0.0)
513 self.assertEqual(round(-123.456, n), -0.0)
514 self.assertEqual(round(1e300, n), 0.0)
515 self.assertEqual(round(1e-320, n), 0.0)
516
517 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
518 "test requires IEEE 754 doubles")
519 def test_overflow(self):
520 self.assertRaises(OverflowError, round, 1.6e308, -308)
521 self.assertRaises(OverflowError, round, -1.7e308, -308)
522
523 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
524 "applies only when using short float repr style")
525 def test_previous_round_bugs(self):
526 # particular cases that have occurred in bug reports
527 self.assertEqual(round(562949953421312.5, 1),
528 562949953421312.5)
529 self.assertEqual(round(56294995342131.5, 3),
530 56294995342131.5)
531 # round-half-even
532 self.assertEqual(round(25.0, -1), 20.0)
533 self.assertEqual(round(35.0, -1), 40.0)
534 self.assertEqual(round(45.0, -1), 40.0)
535 self.assertEqual(round(55.0, -1), 60.0)
536 self.assertEqual(round(65.0, -1), 60.0)
537 self.assertEqual(round(75.0, -1), 80.0)
538 self.assertEqual(round(85.0, -1), 80.0)
539 self.assertEqual(round(95.0, -1), 100.0)
540
541 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
542 "applies only when using short float repr style")
543 def test_matches_float_format(self):
544 # round should give the same results as float formatting
545 for i in range(500):
546 x = i/1000.
547 self.assertEqual(float(format(x, '.0f')), round(x, 0))
548 self.assertEqual(float(format(x, '.1f')), round(x, 1))
549 self.assertEqual(float(format(x, '.2f')), round(x, 2))
550 self.assertEqual(float(format(x, '.3f')), round(x, 3))
551
552 for i in range(5, 5000, 10):
553 x = i/1000.
554 self.assertEqual(float(format(x, '.0f')), round(x, 0))
555 self.assertEqual(float(format(x, '.1f')), round(x, 1))
556 self.assertEqual(float(format(x, '.2f')), round(x, 2))
557 self.assertEqual(float(format(x, '.3f')), round(x, 3))
558
559 for i in range(500):
560 x = random.random()
561 self.assertEqual(float(format(x, '.0f')), round(x, 0))
562 self.assertEqual(float(format(x, '.1f')), round(x, 1))
563 self.assertEqual(float(format(x, '.2f')), round(x, 2))
564 self.assertEqual(float(format(x, '.3f')), round(x, 3))
565
566
567
Christian Heimes99170a52007-12-19 02:07:34 +0000568# Beginning with Python 2.6 float has cross platform compatible
Georg Brandl2ee470f2008-07-16 12:55:28 +0000569# ways to create and represent inf and nan
Christian Heimes99170a52007-12-19 02:07:34 +0000570class InfNanTest(unittest.TestCase):
571 def test_inf_from_str(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000572 self.assertTrue(isinf(float("inf")))
573 self.assertTrue(isinf(float("+inf")))
574 self.assertTrue(isinf(float("-inf")))
575 self.assertTrue(isinf(float("infinity")))
576 self.assertTrue(isinf(float("+infinity")))
577 self.assertTrue(isinf(float("-infinity")))
Christian Heimes99170a52007-12-19 02:07:34 +0000578
579 self.assertEqual(repr(float("inf")), "inf")
580 self.assertEqual(repr(float("+inf")), "inf")
581 self.assertEqual(repr(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000582 self.assertEqual(repr(float("infinity")), "inf")
583 self.assertEqual(repr(float("+infinity")), "inf")
584 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000585
586 self.assertEqual(repr(float("INF")), "inf")
587 self.assertEqual(repr(float("+Inf")), "inf")
588 self.assertEqual(repr(float("-iNF")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000589 self.assertEqual(repr(float("Infinity")), "inf")
590 self.assertEqual(repr(float("+iNfInItY")), "inf")
591 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000592
593 self.assertEqual(str(float("inf")), "inf")
594 self.assertEqual(str(float("+inf")), "inf")
595 self.assertEqual(str(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000596 self.assertEqual(str(float("infinity")), "inf")
597 self.assertEqual(str(float("+infinity")), "inf")
598 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000599
600 self.assertRaises(ValueError, float, "info")
601 self.assertRaises(ValueError, float, "+info")
602 self.assertRaises(ValueError, float, "-info")
603 self.assertRaises(ValueError, float, "in")
604 self.assertRaises(ValueError, float, "+in")
605 self.assertRaises(ValueError, float, "-in")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000606 self.assertRaises(ValueError, float, "infinit")
607 self.assertRaises(ValueError, float, "+Infin")
608 self.assertRaises(ValueError, float, "-INFI")
609 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes99170a52007-12-19 02:07:34 +0000610
Mark Dickinsonbd16edd2009-05-20 22:05:25 +0000611 self.assertRaises(ValueError, float, "++Inf")
612 self.assertRaises(ValueError, float, "-+inf")
613 self.assertRaises(ValueError, float, "+-infinity")
614 self.assertRaises(ValueError, float, "--Infinity")
615
Christian Heimes99170a52007-12-19 02:07:34 +0000616 def test_inf_as_str(self):
617 self.assertEqual(repr(1e300 * 1e300), "inf")
618 self.assertEqual(repr(-1e300 * 1e300), "-inf")
619
620 self.assertEqual(str(1e300 * 1e300), "inf")
621 self.assertEqual(str(-1e300 * 1e300), "-inf")
622
623 def test_nan_from_str(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000624 self.assertTrue(isnan(float("nan")))
625 self.assertTrue(isnan(float("+nan")))
626 self.assertTrue(isnan(float("-nan")))
Christian Heimes99170a52007-12-19 02:07:34 +0000627
628 self.assertEqual(repr(float("nan")), "nan")
629 self.assertEqual(repr(float("+nan")), "nan")
630 self.assertEqual(repr(float("-nan")), "nan")
631
632 self.assertEqual(repr(float("NAN")), "nan")
633 self.assertEqual(repr(float("+NAn")), "nan")
634 self.assertEqual(repr(float("-NaN")), "nan")
635
636 self.assertEqual(str(float("nan")), "nan")
637 self.assertEqual(str(float("+nan")), "nan")
638 self.assertEqual(str(float("-nan")), "nan")
639
640 self.assertRaises(ValueError, float, "nana")
641 self.assertRaises(ValueError, float, "+nana")
642 self.assertRaises(ValueError, float, "-nana")
643 self.assertRaises(ValueError, float, "na")
644 self.assertRaises(ValueError, float, "+na")
645 self.assertRaises(ValueError, float, "-na")
646
Mark Dickinsonbd16edd2009-05-20 22:05:25 +0000647 self.assertRaises(ValueError, float, "++nan")
648 self.assertRaises(ValueError, float, "-+NAN")
649 self.assertRaises(ValueError, float, "+-NaN")
650 self.assertRaises(ValueError, float, "--nAn")
651
Christian Heimes99170a52007-12-19 02:07:34 +0000652 def test_nan_as_str(self):
653 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
654 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
655
656 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
657 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes827b35c2007-12-10 22:19:17 +0000658
Christian Heimes53876d92008-04-19 00:31:39 +0000659 def notest_float_nan(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000660 self.assertTrue(NAN.is_nan())
661 self.assertFalse(INF.is_nan())
662 self.assertFalse((0.).is_nan())
Christian Heimes53876d92008-04-19 00:31:39 +0000663
664 def notest_float_inf(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000665 self.assertTrue(INF.is_inf())
666 self.assertFalse(NAN.is_inf())
667 self.assertFalse((0.).is_inf())
Christian Heimes53876d92008-04-19 00:31:39 +0000668
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000669fromHex = float.fromhex
670toHex = float.hex
671class HexFloatTestCase(unittest.TestCase):
672 MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
673 MIN = fromHex('0x1p-1022') # min normal
674 TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
675 EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
676
677 def identical(self, x, y):
678 # check that floats x and y are identical, or that both
679 # are NaNs
680 if isnan(x) or isnan(y):
681 if isnan(x) == isnan(y):
682 return
683 elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
684 return
685 self.fail('%r not identical to %r' % (x, y))
686
687 def test_ends(self):
Mark Dickinson38bbc482008-07-16 11:32:23 +0000688 self.identical(self.MIN, ldexp(1.0, -1022))
689 self.identical(self.TINY, ldexp(1.0, -1074))
690 self.identical(self.EPS, ldexp(1.0, -52))
691 self.identical(self.MAX, 2.*(ldexp(1.0, 1023) - ldexp(1.0, 970)))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000692
693 def test_invalid_inputs(self):
694 invalid_inputs = [
695 'infi', # misspelt infinities and nans
696 '-Infinit',
697 '++inf',
698 '-+Inf',
699 '--nan',
700 '+-NaN',
701 'snan',
702 'NaNs',
703 'nna',
Mark Dickinsond1ec8b22009-05-11 15:45:15 +0000704 'an',
705 'nf',
706 'nfinity',
707 'inity',
708 'iinity',
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000709 '0xnan',
710 '',
711 ' ',
712 'x1.0p0',
713 '0xX1.0p0',
714 '+ 0x1.0p0', # internal whitespace
715 '- 0x1.0p0',
716 '0 x1.0p0',
717 '0x 1.0p0',
718 '0x1 2.0p0',
719 '+0x1 .0p0',
720 '0x1. 0p0',
721 '-0x1.0 1p0',
722 '-0x1.0 p0',
723 '+0x1.0p +0',
724 '0x1.0p -0',
725 '0x1.0p 0',
726 '+0x1.0p+ 0',
727 '-0x1.0p- 0',
728 '++0x1.0p-0', # double signs
729 '--0x1.0p0',
730 '+-0x1.0p+0',
731 '-+0x1.0p0',
732 '0x1.0p++0',
733 '+0x1.0p+-0',
734 '-0x1.0p-+0',
735 '0x1.0p--0',
736 '0x1.0.p0',
737 '0x.p0', # no hex digits before or after point
738 '0x1,p0', # wrong decimal point character
739 '0x1pa',
740 '0x1p\uff10', # fullwidth Unicode digits
741 '\uff10x1p0',
742 '0x\uff11p0',
743 '0x1.\uff10p0',
744 '0x1p0 \n 0x2p0',
745 '0x1p0\0 0x1p0', # embedded null byte is not end of string
746 ]
747 for x in invalid_inputs:
Mark Dickinson589b7952008-08-21 20:05:56 +0000748 try:
749 result = fromHex(x)
750 except ValueError:
751 pass
752 else:
753 self.fail('Expected float.fromhex(%r) to raise ValueError; '
754 'got %r instead' % (x, result))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000755
756
Mark Dickinsond1ec8b22009-05-11 15:45:15 +0000757 def test_whitespace(self):
758 value_pairs = [
759 ('inf', INF),
760 ('-Infinity', -INF),
761 ('nan', NAN),
762 ('1.0', 1.0),
763 ('-0x.2', -0.125),
764 ('-0.0', -0.0)
765 ]
766 whitespace = [
767 '',
768 ' ',
769 '\t',
770 '\n',
771 '\n \t',
772 '\f',
773 '\v',
774 '\r'
775 ]
776 for inp, expected in value_pairs:
777 for lead in whitespace:
778 for trail in whitespace:
779 got = fromHex(lead + inp + trail)
780 self.identical(got, expected)
781
782
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000783 def test_from_hex(self):
784 MIN = self.MIN;
785 MAX = self.MAX;
786 TINY = self.TINY;
787 EPS = self.EPS;
788
789 # two spellings of infinity, with optional signs; case-insensitive
790 self.identical(fromHex('inf'), INF)
791 self.identical(fromHex('+Inf'), INF)
792 self.identical(fromHex('-INF'), -INF)
793 self.identical(fromHex('iNf'), INF)
794 self.identical(fromHex('Infinity'), INF)
795 self.identical(fromHex('+INFINITY'), INF)
796 self.identical(fromHex('-infinity'), -INF)
797 self.identical(fromHex('-iNFiNitY'), -INF)
798
799 # nans with optional sign; case insensitive
800 self.identical(fromHex('nan'), NAN)
801 self.identical(fromHex('+NaN'), NAN)
802 self.identical(fromHex('-NaN'), NAN)
803 self.identical(fromHex('-nAN'), NAN)
804
805 # variations in input format
806 self.identical(fromHex('1'), 1.0)
807 self.identical(fromHex('+1'), 1.0)
808 self.identical(fromHex('1.'), 1.0)
809 self.identical(fromHex('1.0'), 1.0)
810 self.identical(fromHex('1.0p0'), 1.0)
811 self.identical(fromHex('01'), 1.0)
812 self.identical(fromHex('01.'), 1.0)
813 self.identical(fromHex('0x1'), 1.0)
814 self.identical(fromHex('0x1.'), 1.0)
815 self.identical(fromHex('0x1.0'), 1.0)
816 self.identical(fromHex('+0x1.0'), 1.0)
817 self.identical(fromHex('0x1p0'), 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('0x1.p0'), 1.0)
822 self.identical(fromHex('0x1.0p0'), 1.0)
823 self.identical(fromHex('0x.1p4'), 1.0)
824 self.identical(fromHex('0x.1p04'), 1.0)
825 self.identical(fromHex('0x.1p004'), 1.0)
826 self.identical(fromHex('0x1p+0'), 1.0)
827 self.identical(fromHex('0x1P-0'), 1.0)
828 self.identical(fromHex('+0x1p0'), 1.0)
829 self.identical(fromHex('0x01p0'), 1.0)
830 self.identical(fromHex('0x1p00'), 1.0)
831 self.identical(fromHex(' 0x1p0 '), 1.0)
832 self.identical(fromHex('\n 0x1p0'), 1.0)
833 self.identical(fromHex('0x1p0 \t'), 1.0)
834 self.identical(fromHex('0xap0'), 10.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('0xbep0'), 190.0)
839 self.identical(fromHex('0xBep0'), 190.0)
840 self.identical(fromHex('0xbEp0'), 190.0)
841 self.identical(fromHex('0XBE0P-4'), 190.0)
842 self.identical(fromHex('0xBEp0'), 190.0)
843 self.identical(fromHex('0xB.Ep4'), 190.0)
844 self.identical(fromHex('0x.BEp8'), 190.0)
845 self.identical(fromHex('0x.0BEp12'), 190.0)
846
847 # moving the point around
848 pi = fromHex('0x1.921fb54442d18p1')
849 self.identical(fromHex('0x.006487ed5110b46p11'), pi)
850 self.identical(fromHex('0x.00c90fdaa22168cp10'), pi)
851 self.identical(fromHex('0x.01921fb54442d18p9'), pi)
852 self.identical(fromHex('0x.03243f6a8885a3p8'), pi)
853 self.identical(fromHex('0x.06487ed5110b46p7'), pi)
854 self.identical(fromHex('0x.0c90fdaa22168cp6'), pi)
855 self.identical(fromHex('0x.1921fb54442d18p5'), pi)
856 self.identical(fromHex('0x.3243f6a8885a3p4'), pi)
857 self.identical(fromHex('0x.6487ed5110b46p3'), pi)
858 self.identical(fromHex('0x.c90fdaa22168cp2'), pi)
859 self.identical(fromHex('0x1.921fb54442d18p1'), pi)
860 self.identical(fromHex('0x3.243f6a8885a3p0'), pi)
861 self.identical(fromHex('0x6.487ed5110b46p-1'), pi)
862 self.identical(fromHex('0xc.90fdaa22168cp-2'), pi)
863 self.identical(fromHex('0x19.21fb54442d18p-3'), pi)
864 self.identical(fromHex('0x32.43f6a8885a3p-4'), pi)
865 self.identical(fromHex('0x64.87ed5110b46p-5'), pi)
866 self.identical(fromHex('0xc9.0fdaa22168cp-6'), pi)
867 self.identical(fromHex('0x192.1fb54442d18p-7'), pi)
868 self.identical(fromHex('0x324.3f6a8885a3p-8'), pi)
869 self.identical(fromHex('0x648.7ed5110b46p-9'), pi)
870 self.identical(fromHex('0xc90.fdaa22168cp-10'), pi)
871 self.identical(fromHex('0x1921.fb54442d18p-11'), pi)
872 # ...
873 self.identical(fromHex('0x1921fb54442d1.8p-47'), pi)
874 self.identical(fromHex('0x3243f6a8885a3p-48'), pi)
875 self.identical(fromHex('0x6487ed5110b46p-49'), pi)
876 self.identical(fromHex('0xc90fdaa22168cp-50'), pi)
877 self.identical(fromHex('0x1921fb54442d18p-51'), pi)
878 self.identical(fromHex('0x3243f6a8885a30p-52'), pi)
879 self.identical(fromHex('0x6487ed5110b460p-53'), pi)
880 self.identical(fromHex('0xc90fdaa22168c0p-54'), pi)
881 self.identical(fromHex('0x1921fb54442d180p-55'), pi)
882
883
884 # results that should overflow...
885 self.assertRaises(OverflowError, fromHex, '-0x1p1024')
886 self.assertRaises(OverflowError, fromHex, '0x1p+1025')
887 self.assertRaises(OverflowError, fromHex, '+0X1p1030')
888 self.assertRaises(OverflowError, fromHex, '-0x1p+1100')
889 self.assertRaises(OverflowError, fromHex, '0X1p123456789123456789')
890 self.assertRaises(OverflowError, fromHex, '+0X.8p+1025')
891 self.assertRaises(OverflowError, fromHex, '+0x0.8p1025')
892 self.assertRaises(OverflowError, fromHex, '-0x0.4p1026')
893 self.assertRaises(OverflowError, fromHex, '0X2p+1023')
894 self.assertRaises(OverflowError, fromHex, '0x2.p1023')
895 self.assertRaises(OverflowError, fromHex, '-0x2.0p+1023')
896 self.assertRaises(OverflowError, fromHex, '+0X4p+1022')
897 self.assertRaises(OverflowError, fromHex, '0x1.ffffffffffffffp+1023')
898 self.assertRaises(OverflowError, fromHex, '-0X1.fffffffffffff9p1023')
899 self.assertRaises(OverflowError, fromHex, '0X1.fffffffffffff8p1023')
900 self.assertRaises(OverflowError, fromHex, '+0x3.fffffffffffffp1022')
901 self.assertRaises(OverflowError, fromHex, '0x3fffffffffffffp+970')
902 self.assertRaises(OverflowError, fromHex, '0x10000000000000000p960')
903 self.assertRaises(OverflowError, fromHex, '-0Xffffffffffffffffp960')
904
905 # ...and those that round to +-max float
906 self.identical(fromHex('+0x1.fffffffffffffp+1023'), MAX)
907 self.identical(fromHex('-0X1.fffffffffffff7p1023'), -MAX)
908 self.identical(fromHex('0X1.fffffffffffff7fffffffffffffp1023'), MAX)
909
910 # zeros
911 self.identical(fromHex('0x0p0'), 0.0)
912 self.identical(fromHex('0x0p1000'), 0.0)
913 self.identical(fromHex('-0x0p1023'), -0.0)
914 self.identical(fromHex('0X0p1024'), 0.0)
915 self.identical(fromHex('-0x0p1025'), -0.0)
916 self.identical(fromHex('0X0p2000'), 0.0)
917 self.identical(fromHex('0x0p123456789123456789'), 0.0)
918 self.identical(fromHex('-0X0p-0'), -0.0)
919 self.identical(fromHex('-0X0p-1000'), -0.0)
920 self.identical(fromHex('0x0p-1023'), 0.0)
921 self.identical(fromHex('-0X0p-1024'), -0.0)
922 self.identical(fromHex('-0x0p-1025'), -0.0)
923 self.identical(fromHex('-0x0p-1072'), -0.0)
924 self.identical(fromHex('0X0p-1073'), 0.0)
925 self.identical(fromHex('-0x0p-1074'), -0.0)
926 self.identical(fromHex('0x0p-1075'), 0.0)
927 self.identical(fromHex('0X0p-1076'), 0.0)
928 self.identical(fromHex('-0X0p-2000'), -0.0)
929 self.identical(fromHex('-0x0p-123456789123456789'), -0.0)
930
931 # values that should underflow to 0
932 self.identical(fromHex('0X1p-1075'), 0.0)
933 self.identical(fromHex('-0X1p-1075'), -0.0)
934 self.identical(fromHex('-0x1p-123456789123456789'), -0.0)
935 self.identical(fromHex('0x1.00000000000000001p-1075'), TINY)
936 self.identical(fromHex('-0x1.1p-1075'), -TINY)
937 self.identical(fromHex('0x1.fffffffffffffffffp-1075'), TINY)
938
939 # check round-half-even is working correctly near 0 ...
940 self.identical(fromHex('0x1p-1076'), 0.0)
941 self.identical(fromHex('0X2p-1076'), 0.0)
942 self.identical(fromHex('0X3p-1076'), TINY)
943 self.identical(fromHex('0x4p-1076'), TINY)
944 self.identical(fromHex('0X5p-1076'), TINY)
945 self.identical(fromHex('0X6p-1076'), 2*TINY)
946 self.identical(fromHex('0x7p-1076'), 2*TINY)
947 self.identical(fromHex('0X8p-1076'), 2*TINY)
948 self.identical(fromHex('0X9p-1076'), 2*TINY)
949 self.identical(fromHex('0xap-1076'), 2*TINY)
950 self.identical(fromHex('0Xbp-1076'), 3*TINY)
951 self.identical(fromHex('0xcp-1076'), 3*TINY)
952 self.identical(fromHex('0Xdp-1076'), 3*TINY)
953 self.identical(fromHex('0Xep-1076'), 4*TINY)
954 self.identical(fromHex('0xfp-1076'), 4*TINY)
955 self.identical(fromHex('0x10p-1076'), 4*TINY)
956 self.identical(fromHex('-0x1p-1076'), -0.0)
957 self.identical(fromHex('-0X2p-1076'), -0.0)
958 self.identical(fromHex('-0x3p-1076'), -TINY)
959 self.identical(fromHex('-0X4p-1076'), -TINY)
960 self.identical(fromHex('-0x5p-1076'), -TINY)
961 self.identical(fromHex('-0x6p-1076'), -2*TINY)
962 self.identical(fromHex('-0X7p-1076'), -2*TINY)
963 self.identical(fromHex('-0X8p-1076'), -2*TINY)
964 self.identical(fromHex('-0X9p-1076'), -2*TINY)
965 self.identical(fromHex('-0Xap-1076'), -2*TINY)
966 self.identical(fromHex('-0xbp-1076'), -3*TINY)
967 self.identical(fromHex('-0xcp-1076'), -3*TINY)
968 self.identical(fromHex('-0Xdp-1076'), -3*TINY)
969 self.identical(fromHex('-0xep-1076'), -4*TINY)
970 self.identical(fromHex('-0Xfp-1076'), -4*TINY)
971 self.identical(fromHex('-0X10p-1076'), -4*TINY)
972
973 # ... and near MIN ...
974 self.identical(fromHex('0x0.ffffffffffffd6p-1022'), MIN-3*TINY)
975 self.identical(fromHex('0x0.ffffffffffffd8p-1022'), MIN-2*TINY)
976 self.identical(fromHex('0x0.ffffffffffffdap-1022'), MIN-2*TINY)
977 self.identical(fromHex('0x0.ffffffffffffdcp-1022'), MIN-2*TINY)
978 self.identical(fromHex('0x0.ffffffffffffdep-1022'), MIN-2*TINY)
979 self.identical(fromHex('0x0.ffffffffffffe0p-1022'), MIN-2*TINY)
980 self.identical(fromHex('0x0.ffffffffffffe2p-1022'), MIN-2*TINY)
981 self.identical(fromHex('0x0.ffffffffffffe4p-1022'), MIN-2*TINY)
982 self.identical(fromHex('0x0.ffffffffffffe6p-1022'), MIN-2*TINY)
983 self.identical(fromHex('0x0.ffffffffffffe8p-1022'), MIN-2*TINY)
984 self.identical(fromHex('0x0.ffffffffffffeap-1022'), MIN-TINY)
985 self.identical(fromHex('0x0.ffffffffffffecp-1022'), MIN-TINY)
986 self.identical(fromHex('0x0.ffffffffffffeep-1022'), MIN-TINY)
987 self.identical(fromHex('0x0.fffffffffffff0p-1022'), MIN-TINY)
988 self.identical(fromHex('0x0.fffffffffffff2p-1022'), MIN-TINY)
989 self.identical(fromHex('0x0.fffffffffffff4p-1022'), MIN-TINY)
990 self.identical(fromHex('0x0.fffffffffffff6p-1022'), MIN-TINY)
991 self.identical(fromHex('0x0.fffffffffffff8p-1022'), MIN)
992 self.identical(fromHex('0x0.fffffffffffffap-1022'), MIN)
993 self.identical(fromHex('0x0.fffffffffffffcp-1022'), MIN)
994 self.identical(fromHex('0x0.fffffffffffffep-1022'), MIN)
995 self.identical(fromHex('0x1.00000000000000p-1022'), MIN)
996 self.identical(fromHex('0x1.00000000000002p-1022'), MIN)
997 self.identical(fromHex('0x1.00000000000004p-1022'), MIN)
998 self.identical(fromHex('0x1.00000000000006p-1022'), MIN)
999 self.identical(fromHex('0x1.00000000000008p-1022'), MIN)
1000 self.identical(fromHex('0x1.0000000000000ap-1022'), MIN+TINY)
1001 self.identical(fromHex('0x1.0000000000000cp-1022'), MIN+TINY)
1002 self.identical(fromHex('0x1.0000000000000ep-1022'), MIN+TINY)
1003 self.identical(fromHex('0x1.00000000000010p-1022'), MIN+TINY)
1004 self.identical(fromHex('0x1.00000000000012p-1022'), MIN+TINY)
1005 self.identical(fromHex('0x1.00000000000014p-1022'), MIN+TINY)
1006 self.identical(fromHex('0x1.00000000000016p-1022'), MIN+TINY)
1007 self.identical(fromHex('0x1.00000000000018p-1022'), MIN+2*TINY)
1008
1009 # ... and near 1.0.
1010 self.identical(fromHex('0x0.fffffffffffff0p0'), 1.0-EPS)
1011 self.identical(fromHex('0x0.fffffffffffff1p0'), 1.0-EPS)
1012 self.identical(fromHex('0X0.fffffffffffff2p0'), 1.0-EPS)
1013 self.identical(fromHex('0x0.fffffffffffff3p0'), 1.0-EPS)
1014 self.identical(fromHex('0X0.fffffffffffff4p0'), 1.0-EPS)
1015 self.identical(fromHex('0X0.fffffffffffff5p0'), 1.0-EPS/2)
1016 self.identical(fromHex('0X0.fffffffffffff6p0'), 1.0-EPS/2)
1017 self.identical(fromHex('0x0.fffffffffffff7p0'), 1.0-EPS/2)
1018 self.identical(fromHex('0x0.fffffffffffff8p0'), 1.0-EPS/2)
1019 self.identical(fromHex('0X0.fffffffffffff9p0'), 1.0-EPS/2)
1020 self.identical(fromHex('0X0.fffffffffffffap0'), 1.0-EPS/2)
1021 self.identical(fromHex('0x0.fffffffffffffbp0'), 1.0-EPS/2)
1022 self.identical(fromHex('0X0.fffffffffffffcp0'), 1.0)
1023 self.identical(fromHex('0x0.fffffffffffffdp0'), 1.0)
1024 self.identical(fromHex('0X0.fffffffffffffep0'), 1.0)
1025 self.identical(fromHex('0x0.ffffffffffffffp0'), 1.0)
1026 self.identical(fromHex('0X1.00000000000000p0'), 1.0)
1027 self.identical(fromHex('0X1.00000000000001p0'), 1.0)
1028 self.identical(fromHex('0x1.00000000000002p0'), 1.0)
1029 self.identical(fromHex('0X1.00000000000003p0'), 1.0)
1030 self.identical(fromHex('0x1.00000000000004p0'), 1.0)
1031 self.identical(fromHex('0X1.00000000000005p0'), 1.0)
1032 self.identical(fromHex('0X1.00000000000006p0'), 1.0)
1033 self.identical(fromHex('0X1.00000000000007p0'), 1.0)
1034 self.identical(fromHex('0x1.00000000000007ffffffffffffffffffffp0'),
1035 1.0)
1036 self.identical(fromHex('0x1.00000000000008p0'), 1.0)
1037 self.identical(fromHex('0x1.00000000000008000000000000000001p0'),
1038 1+EPS)
1039 self.identical(fromHex('0X1.00000000000009p0'), 1.0+EPS)
1040 self.identical(fromHex('0x1.0000000000000ap0'), 1.0+EPS)
1041 self.identical(fromHex('0x1.0000000000000bp0'), 1.0+EPS)
1042 self.identical(fromHex('0X1.0000000000000cp0'), 1.0+EPS)
1043 self.identical(fromHex('0x1.0000000000000dp0'), 1.0+EPS)
1044 self.identical(fromHex('0x1.0000000000000ep0'), 1.0+EPS)
1045 self.identical(fromHex('0X1.0000000000000fp0'), 1.0+EPS)
1046 self.identical(fromHex('0x1.00000000000010p0'), 1.0+EPS)
1047 self.identical(fromHex('0X1.00000000000011p0'), 1.0+EPS)
1048 self.identical(fromHex('0x1.00000000000012p0'), 1.0+EPS)
1049 self.identical(fromHex('0X1.00000000000013p0'), 1.0+EPS)
1050 self.identical(fromHex('0X1.00000000000014p0'), 1.0+EPS)
1051 self.identical(fromHex('0x1.00000000000015p0'), 1.0+EPS)
1052 self.identical(fromHex('0x1.00000000000016p0'), 1.0+EPS)
1053 self.identical(fromHex('0X1.00000000000017p0'), 1.0+EPS)
1054 self.identical(fromHex('0x1.00000000000017ffffffffffffffffffffp0'),
1055 1.0+EPS)
1056 self.identical(fromHex('0x1.00000000000018p0'), 1.0+2*EPS)
1057 self.identical(fromHex('0X1.00000000000018000000000000000001p0'),
1058 1.0+2*EPS)
1059 self.identical(fromHex('0x1.00000000000019p0'), 1.0+2*EPS)
1060 self.identical(fromHex('0X1.0000000000001ap0'), 1.0+2*EPS)
1061 self.identical(fromHex('0X1.0000000000001bp0'), 1.0+2*EPS)
1062 self.identical(fromHex('0x1.0000000000001cp0'), 1.0+2*EPS)
1063 self.identical(fromHex('0x1.0000000000001dp0'), 1.0+2*EPS)
1064 self.identical(fromHex('0x1.0000000000001ep0'), 1.0+2*EPS)
1065 self.identical(fromHex('0X1.0000000000001fp0'), 1.0+2*EPS)
1066 self.identical(fromHex('0x1.00000000000020p0'), 1.0+2*EPS)
1067
1068 def test_roundtrip(self):
1069 def roundtrip(x):
1070 return fromHex(toHex(x))
1071
1072 for x in [NAN, INF, self.MAX, self.MIN, self.MIN-self.TINY, self.TINY, 0.0]:
1073 self.identical(x, roundtrip(x))
1074 self.identical(-x, roundtrip(-x))
1075
1076 # fromHex(toHex(x)) should exactly recover x, for any non-NaN float x.
1077 import random
1078 for i in range(10000):
1079 e = random.randrange(-1200, 1200)
1080 m = random.random()
1081 s = random.choice([1.0, -1.0])
1082 try:
1083 x = s*ldexp(m, e)
1084 except OverflowError:
1085 pass
1086 else:
1087 self.identical(x, fromHex(toHex(x)))
1088
Mark Dickinson46672512010-01-12 23:09:26 +00001089class StrtodTestCase(unittest.TestCase):
1090 def check_string(self, s):
1091 expected = strtod(s)
1092 try:
1093 fs = float(s)
1094 except OverflowError:
1095 got = '-inf' if s[0] == '-' else 'inf'
1096 else:
1097 got = fs.hex()
1098 self.assertEqual(expected, got,
1099 "Incorrectly rounded str->float conversion for "
1100 "{}: expected {}, got {}".format(s, expected, got))
1101
1102 @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
1103 "applies only when using short float repr style")
1104 def test_bug7632(self):
1105 # check a few particular values that gave incorrectly rounded
1106 # results with previous versions of dtoa.c
1107 test_strings = [
1108 '94393431193180696942841837085033647913224148539854e-358',
1109 '12579816049008305546974391768996369464963024663104e-357',
1110 '17489628565202117263145367596028389348922981857013e-357',
1111 '18487398785991994634182916638542680759613590482273e-357',
1112 '32002864200581033134358724675198044527469366773928e-358',
1113 '73608278998966969345824653500136787876436005957953e-358',
1114 '64774478836417299491718435234611299336288082136054e-358',
1115 '13704940134126574534878641876947980878824688451169e-357',
1116 '46697445774047060960624497964425416610480524760471e-358',
1117 ]
1118 for s in test_strings:
1119 self.check_string(s)
1120
Christian Heimes53876d92008-04-19 00:31:39 +00001121
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001122def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001123 support.run_unittest(
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +00001124 GeneralFloatCases,
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001125 FormatFunctionsTestCase,
1126 UnknownFormatTestCase,
Eric Smith8c663262007-08-25 02:26:07 +00001127 IEEEFormatTestCase,
Christian Heimes827b35c2007-12-10 22:19:17 +00001128 FormatTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +00001129 ReprTestCase,
Mark Dickinsone6a076d2009-04-18 11:48:33 +00001130 RoundTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +00001131 InfNanTest,
Mark Dickinson65fe25e2008-07-16 11:30:51 +00001132 HexFloatTestCase,
Mark Dickinson46672512010-01-12 23:09:26 +00001133 StrtodTestCase,
Christian Heimesb76922a2007-12-11 01:06:40 +00001134 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001135
1136if __name__ == '__main__':
1137 test_main()