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