blob: 9d0c69d4c063cbdcb303e06f151f42574e5f58a1 [file] [log] [blame]
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001
2import unittest, struct
Christian Heimes284d9272007-12-10 22:28:56 +00003import os
Michael W. Hudsonba283e22005-05-27 15:23:20 +00004from test import test_support
Christian Heimes6f341092008-04-18 23:13:07 +00005import math
Mark Dickinson7103aa42008-07-15 19:08:33 +00006from math import isinf, isnan, copysign, ldexp
Christian Heimes6f341092008-04-18 23:13:07 +00007import operator
Amaury Forgeot d'Arcfeb8cad2008-09-06 20:53:51 +00008import random, fractions
Michael W. Hudsonba283e22005-05-27 15:23:20 +00009
Christian Heimes6f341092008-04-18 23:13:07 +000010INF = float("inf")
11NAN = float("nan")
Christian Heimes0a8143f2007-12-18 23:22:54 +000012
Mark Dickinson61a0d052009-04-29 21:57:15 +000013#locate file with float format test values
14test_dir = os.path.dirname(__file__) or os.curdir
15format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
16
Benjamin Peterson979395b2008-05-03 21:35:18 +000017class GeneralFloatCases(unittest.TestCase):
18
19 def test_float(self):
20 self.assertEqual(float(3.14), 3.14)
21 self.assertEqual(float(314), 314.0)
22 self.assertEqual(float(314L), 314.0)
23 self.assertEqual(float(" 3.14 "), 3.14)
24 self.assertRaises(ValueError, float, " 0x3.1 ")
25 self.assertRaises(ValueError, float, " -0x3.p-1 ")
26 self.assertRaises(ValueError, float, " +0x3.p-1 ")
27 self.assertRaises(ValueError, float, "++3.14")
28 self.assertRaises(ValueError, float, "+-3.14")
29 self.assertRaises(ValueError, float, "-+3.14")
30 self.assertRaises(ValueError, float, "--3.14")
Amaury Forgeot d'Arcfeb8cad2008-09-06 20:53:51 +000031 if test_support.have_unicode:
Benjamin Peterson979395b2008-05-03 21:35:18 +000032 self.assertEqual(float(unicode(" 3.14 ")), 3.14)
33 self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
Benjamin Peterson979395b2008-05-03 21:35:18 +000034
35 @test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
36 def test_float_with_comma(self):
37 # set locale to something that doesn't use '.' for the decimal point
38 # float must not accept the locale specific decimal point but
39 # it still has to accept the normal python syntac
40 import locale
41 if not locale.localeconv()['decimal_point'] == ',':
42 return
43
44 self.assertEqual(float(" 3.14 "), 3.14)
45 self.assertEqual(float("+3.14 "), 3.14)
46 self.assertEqual(float("-3.14 "), -3.14)
47 self.assertEqual(float(".14 "), .14)
48 self.assertEqual(float("3. "), 3.0)
49 self.assertEqual(float("3.e3 "), 3000.0)
50 self.assertEqual(float("3.2e3 "), 3200.0)
51 self.assertEqual(float("2.5e-1 "), 0.25)
52 self.assertEqual(float("5e-1"), 0.5)
53 self.assertRaises(ValueError, float, " 3,14 ")
54 self.assertRaises(ValueError, float, " +3,14 ")
55 self.assertRaises(ValueError, float, " -3,14 ")
56 self.assertRaises(ValueError, float, " 0x3.1 ")
57 self.assertRaises(ValueError, float, " -0x3.p-1 ")
58 self.assertRaises(ValueError, float, " +0x3.p-1 ")
59 self.assertEqual(float(" 25.e-1 "), 2.5)
Benjamin Petersona853a892008-09-06 23:19:15 +000060 self.assertEqual(test_support.fcmp(float(" .25e-1 "), .025), 0)
Benjamin Peterson979395b2008-05-03 21:35:18 +000061
62 def test_floatconversion(self):
63 # Make sure that calls to __float__() work properly
64 class Foo0:
65 def __float__(self):
66 return 42.
67
68 class Foo1(object):
69 def __float__(self):
70 return 42.
71
72 class Foo2(float):
73 def __float__(self):
74 return 42.
75
76 class Foo3(float):
77 def __new__(cls, value=0.):
78 return float.__new__(cls, 2*value)
79
80 def __float__(self):
81 return self
82
83 class Foo4(float):
84 def __float__(self):
85 return 42
86
Benjamin Peterson99d36f12009-04-15 21:26:36 +000087 # Issue 5759: __float__ not called on str subclasses (though it is on
88 # unicode subclasses).
89 class FooStr(str):
90 def __float__(self):
91 return float(str(self)) + 1
92
93 class FooUnicode(unicode):
94 def __float__(self):
95 return float(unicode(self)) + 1
96
Benjamin Peterson979395b2008-05-03 21:35:18 +000097 self.assertAlmostEqual(float(Foo0()), 42.)
98 self.assertAlmostEqual(float(Foo1()), 42.)
99 self.assertAlmostEqual(float(Foo2()), 42.)
100 self.assertAlmostEqual(float(Foo3(21)), 42.)
101 self.assertRaises(TypeError, float, Foo4(42))
Benjamin Peterson99d36f12009-04-15 21:26:36 +0000102 self.assertAlmostEqual(float(FooUnicode('8')), 9.)
103 self.assertAlmostEqual(float(FooStr('8')), 9.)
Benjamin Peterson979395b2008-05-03 21:35:18 +0000104
105 def test_floatasratio(self):
106 for f, ratio in [
107 (0.875, (7, 8)),
108 (-0.875, (-7, 8)),
109 (0.0, (0, 1)),
110 (11.5, (23, 2)),
111 ]:
112 self.assertEqual(f.as_integer_ratio(), ratio)
113
114 for i in range(10000):
115 f = random.random()
116 f *= 10 ** random.randint(-100, 100)
117 n, d = f.as_integer_ratio()
118 self.assertEqual(float(n).__truediv__(d), f)
119
120 R = fractions.Fraction
121 self.assertEqual(R(0, 1),
122 R(*float(0.0).as_integer_ratio()))
123 self.assertEqual(R(5, 2),
124 R(*float(2.5).as_integer_ratio()))
125 self.assertEqual(R(1, 2),
126 R(*float(0.5).as_integer_ratio()))
127 self.assertEqual(R(4728779608739021, 2251799813685248),
128 R(*float(2.1).as_integer_ratio()))
129 self.assertEqual(R(-4728779608739021, 2251799813685248),
130 R(*float(-2.1).as_integer_ratio()))
131 self.assertEqual(R(-2100, 1),
132 R(*float(-2100.0).as_integer_ratio()))
133
134 self.assertRaises(OverflowError, float('inf').as_integer_ratio)
135 self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
136 self.assertRaises(ValueError, float('nan').as_integer_ratio)
137
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000138class FormatFunctionsTestCase(unittest.TestCase):
139
140 def setUp(self):
141 self.save_formats = {'double':float.__getformat__('double'),
142 'float':float.__getformat__('float')}
143
144 def tearDown(self):
145 float.__setformat__('double', self.save_formats['double'])
146 float.__setformat__('float', self.save_formats['float'])
147
148 def test_getformat(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000149 self.assertTrue(float.__getformat__('double') in
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000150 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000151 self.assertTrue(float.__getformat__('float') in
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000152 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
153 self.assertRaises(ValueError, float.__getformat__, 'chicken')
154 self.assertRaises(TypeError, float.__getformat__, 1)
155
156 def test_setformat(self):
157 for t in 'double', 'float':
158 float.__setformat__(t, 'unknown')
159 if self.save_formats[t] == 'IEEE, big-endian':
160 self.assertRaises(ValueError, float.__setformat__,
161 t, 'IEEE, little-endian')
162 elif self.save_formats[t] == 'IEEE, little-endian':
163 self.assertRaises(ValueError, float.__setformat__,
164 t, 'IEEE, big-endian')
165 else:
166 self.assertRaises(ValueError, float.__setformat__,
167 t, 'IEEE, big-endian')
168 self.assertRaises(ValueError, float.__setformat__,
169 t, 'IEEE, little-endian')
170 self.assertRaises(ValueError, float.__setformat__,
171 t, 'chicken')
172 self.assertRaises(ValueError, float.__setformat__,
173 'chicken', 'unknown')
174
175BE_DOUBLE_INF = '\x7f\xf0\x00\x00\x00\x00\x00\x00'
176LE_DOUBLE_INF = ''.join(reversed(BE_DOUBLE_INF))
177BE_DOUBLE_NAN = '\x7f\xf8\x00\x00\x00\x00\x00\x00'
178LE_DOUBLE_NAN = ''.join(reversed(BE_DOUBLE_NAN))
179
180BE_FLOAT_INF = '\x7f\x80\x00\x00'
181LE_FLOAT_INF = ''.join(reversed(BE_FLOAT_INF))
182BE_FLOAT_NAN = '\x7f\xc0\x00\x00'
183LE_FLOAT_NAN = ''.join(reversed(BE_FLOAT_NAN))
184
185# on non-IEEE platforms, attempting to unpack a bit pattern
186# representing an infinity or a NaN should raise an exception.
187
188class UnknownFormatTestCase(unittest.TestCase):
189 def setUp(self):
190 self.save_formats = {'double':float.__getformat__('double'),
191 'float':float.__getformat__('float')}
192 float.__setformat__('double', 'unknown')
193 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000194
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000195 def tearDown(self):
196 float.__setformat__('double', self.save_formats['double'])
197 float.__setformat__('float', self.save_formats['float'])
198
199 def test_double_specials_dont_unpack(self):
200 for fmt, data in [('>d', BE_DOUBLE_INF),
201 ('>d', BE_DOUBLE_NAN),
202 ('<d', LE_DOUBLE_INF),
203 ('<d', LE_DOUBLE_NAN)]:
204 self.assertRaises(ValueError, struct.unpack, fmt, data)
205
206 def test_float_specials_dont_unpack(self):
207 for fmt, data in [('>f', BE_FLOAT_INF),
208 ('>f', BE_FLOAT_NAN),
209 ('<f', LE_FLOAT_INF),
210 ('<f', LE_FLOAT_NAN)]:
211 self.assertRaises(ValueError, struct.unpack, fmt, data)
212
213
214# on an IEEE platform, all we guarantee is that bit patterns
215# representing infinities or NaNs do not raise an exception; all else
216# is accident (today).
Alex Martellid8672aa2007-08-22 21:14:17 +0000217# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000218
219class IEEEFormatTestCase(unittest.TestCase):
220 if float.__getformat__("double").startswith("IEEE"):
221 def test_double_specials_do_unpack(self):
222 for fmt, data in [('>d', BE_DOUBLE_INF),
223 ('>d', BE_DOUBLE_NAN),
224 ('<d', LE_DOUBLE_INF),
225 ('<d', LE_DOUBLE_NAN)]:
226 struct.unpack(fmt, data)
227
228 if float.__getformat__("float").startswith("IEEE"):
229 def test_float_specials_do_unpack(self):
230 for fmt, data in [('>f', BE_FLOAT_INF),
231 ('>f', BE_FLOAT_NAN),
232 ('<f', LE_FLOAT_INF),
233 ('<f', LE_FLOAT_NAN)]:
234 struct.unpack(fmt, data)
235
Alex Martellid8672aa2007-08-22 21:14:17 +0000236 if float.__getformat__("double").startswith("IEEE"):
237 def test_negative_zero(self):
238 import math
239 def pos_pos():
240 return 0.0, math.atan2(0.0, -1)
241 def pos_neg():
242 return 0.0, math.atan2(-0.0, -1)
243 def neg_pos():
244 return -0.0, math.atan2(0.0, -1)
245 def neg_neg():
246 return -0.0, math.atan2(-0.0, -1)
247 self.assertEquals(pos_pos(), neg_pos())
248 self.assertEquals(pos_neg(), neg_neg())
249
Guido van Rossum3b835492008-01-05 00:59:59 +0000250 if float.__getformat__("double").startswith("IEEE"):
251 def test_underflow_sign(self):
252 import math
253 # check that -1e-1000 gives -0.0, not 0.0
254 self.assertEquals(math.atan2(-1e-1000, -1), math.atan2(-0.0, -1))
255 self.assertEquals(math.atan2(float('-1e-1000'), -1),
256 math.atan2(-0.0, -1))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000257
Eric Smitha985a3a2009-05-05 18:26:08 +0000258 def test_format(self):
259 # these should be rewritten to use both format(x, spec) and
260 # x.__format__(spec)
261
262 self.assertEqual(format(0.0, 'f'), '0.000000')
263
264 # the default is 'g', except for empty format spec
265 self.assertEqual(format(0.0, ''), '0.0')
266 self.assertEqual(format(0.01, ''), '0.01')
267 self.assertEqual(format(0.01, 'g'), '0.01')
268
269 # empty presentation type should format in the same way as str
270 # (issue 5920)
271 x = 100/7.
272 self.assertEqual(format(x, ''), str(x))
273 self.assertEqual(format(x, '-'), str(x))
274 self.assertEqual(format(x, '>'), str(x))
275 self.assertEqual(format(x, '2'), str(x))
276
277 self.assertEqual(format(1.0, 'f'), '1.000000')
278
279 self.assertEqual(format(-1.0, 'f'), '-1.000000')
280
281 self.assertEqual(format( 1.0, ' f'), ' 1.000000')
282 self.assertEqual(format(-1.0, ' f'), '-1.000000')
283 self.assertEqual(format( 1.0, '+f'), '+1.000000')
284 self.assertEqual(format(-1.0, '+f'), '-1.000000')
285
286 # % formatting
287 self.assertEqual(format(-1.0, '%'), '-100.000000%')
288
289 # conversion to string should fail
290 self.assertRaises(ValueError, format, 3.0, "s")
291
292 # other format specifiers shouldn't work on floats,
293 # in particular int specifiers
294 for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
295 [chr(x) for x in range(ord('A'), ord('Z')+1)]):
296 if not format_spec in 'eEfFgGn%':
297 self.assertRaises(ValueError, format, 0.0, format_spec)
298 self.assertRaises(ValueError, format, 1.0, format_spec)
299 self.assertRaises(ValueError, format, -1.0, format_spec)
300 self.assertRaises(ValueError, format, 1e100, format_spec)
301 self.assertRaises(ValueError, format, -1e100, format_spec)
302 self.assertRaises(ValueError, format, 1e-100, format_spec)
303 self.assertRaises(ValueError, format, -1e-100, format_spec)
304
Mark Dickinson61a0d052009-04-29 21:57:15 +0000305 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
306 "test requires IEEE 754 doubles")
307 def test_format_testfile(self):
308 for line in open(format_testfile):
309 if line.startswith('--'):
310 continue
311 line = line.strip()
312 if not line:
313 continue
314
315 lhs, rhs = map(str.strip, line.split('->'))
316 fmt, arg = lhs.split()
317 self.assertEqual(fmt % float(arg), rhs)
318 self.assertEqual(fmt % -float(arg), '-' + rhs)
319
Mark Dickinson92fcc9c2009-04-29 20:41:00 +0000320 def test_issue5864(self):
321 self.assertEquals(format(123.456, '.4'), '123.5')
322 self.assertEquals(format(1234.56, '.4'), '1.235e+03')
323 self.assertEquals(format(12345.6, '.4'), '1.235e+04')
324
Christian Heimes284d9272007-12-10 22:28:56 +0000325class ReprTestCase(unittest.TestCase):
326 def test_repr(self):
327 floats_file = open(os.path.join(os.path.split(__file__)[0],
328 'floating_points.txt'))
329 for line in floats_file:
330 line = line.strip()
331 if not line or line.startswith('#'):
332 continue
333 v = eval(line)
334 self.assertEqual(v, eval(repr(v)))
335 floats_file.close()
336
Christian Heimes0a8143f2007-12-18 23:22:54 +0000337# Beginning with Python 2.6 float has cross platform compatible
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000338# ways to create and represent inf and nan
Christian Heimes0a8143f2007-12-18 23:22:54 +0000339class InfNanTest(unittest.TestCase):
340 def test_inf_from_str(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000341 self.assertTrue(isinf(float("inf")))
342 self.assertTrue(isinf(float("+inf")))
343 self.assertTrue(isinf(float("-inf")))
344 self.assertTrue(isinf(float("infinity")))
345 self.assertTrue(isinf(float("+infinity")))
346 self.assertTrue(isinf(float("-infinity")))
Christian Heimes0a8143f2007-12-18 23:22:54 +0000347
348 self.assertEqual(repr(float("inf")), "inf")
349 self.assertEqual(repr(float("+inf")), "inf")
350 self.assertEqual(repr(float("-inf")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000351 self.assertEqual(repr(float("infinity")), "inf")
352 self.assertEqual(repr(float("+infinity")), "inf")
353 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000354
355 self.assertEqual(repr(float("INF")), "inf")
356 self.assertEqual(repr(float("+Inf")), "inf")
357 self.assertEqual(repr(float("-iNF")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000358 self.assertEqual(repr(float("Infinity")), "inf")
359 self.assertEqual(repr(float("+iNfInItY")), "inf")
360 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000361
362 self.assertEqual(str(float("inf")), "inf")
363 self.assertEqual(str(float("+inf")), "inf")
364 self.assertEqual(str(float("-inf")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000365 self.assertEqual(str(float("infinity")), "inf")
366 self.assertEqual(str(float("+infinity")), "inf")
367 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000368
369 self.assertRaises(ValueError, float, "info")
370 self.assertRaises(ValueError, float, "+info")
371 self.assertRaises(ValueError, float, "-info")
372 self.assertRaises(ValueError, float, "in")
373 self.assertRaises(ValueError, float, "+in")
374 self.assertRaises(ValueError, float, "-in")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000375 self.assertRaises(ValueError, float, "infinit")
376 self.assertRaises(ValueError, float, "+Infin")
377 self.assertRaises(ValueError, float, "-INFI")
378 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000379
380 def test_inf_as_str(self):
381 self.assertEqual(repr(1e300 * 1e300), "inf")
382 self.assertEqual(repr(-1e300 * 1e300), "-inf")
383
384 self.assertEqual(str(1e300 * 1e300), "inf")
385 self.assertEqual(str(-1e300 * 1e300), "-inf")
386
387 def test_nan_from_str(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000388 self.assertTrue(isnan(float("nan")))
389 self.assertTrue(isnan(float("+nan")))
390 self.assertTrue(isnan(float("-nan")))
Christian Heimes0a8143f2007-12-18 23:22:54 +0000391
392 self.assertEqual(repr(float("nan")), "nan")
393 self.assertEqual(repr(float("+nan")), "nan")
394 self.assertEqual(repr(float("-nan")), "nan")
395
396 self.assertEqual(repr(float("NAN")), "nan")
397 self.assertEqual(repr(float("+NAn")), "nan")
398 self.assertEqual(repr(float("-NaN")), "nan")
399
400 self.assertEqual(str(float("nan")), "nan")
401 self.assertEqual(str(float("+nan")), "nan")
402 self.assertEqual(str(float("-nan")), "nan")
403
404 self.assertRaises(ValueError, float, "nana")
405 self.assertRaises(ValueError, float, "+nana")
406 self.assertRaises(ValueError, float, "-nana")
407 self.assertRaises(ValueError, float, "na")
408 self.assertRaises(ValueError, float, "+na")
409 self.assertRaises(ValueError, float, "-na")
410
411 def test_nan_as_str(self):
412 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
413 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
414
415 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
416 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes284d9272007-12-10 22:28:56 +0000417
Christian Heimes6f341092008-04-18 23:13:07 +0000418 def notest_float_nan(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000419 self.assertTrue(NAN.is_nan())
420 self.assertFalse(INF.is_nan())
421 self.assertFalse((0.).is_nan())
Christian Heimes6f341092008-04-18 23:13:07 +0000422
423 def notest_float_inf(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000424 self.assertTrue(INF.is_inf())
425 self.assertFalse(NAN.is_inf())
426 self.assertFalse((0.).is_inf())
Christian Heimes6f341092008-04-18 23:13:07 +0000427
Mark Dickinson7103aa42008-07-15 19:08:33 +0000428fromHex = float.fromhex
429toHex = float.hex
430class HexFloatTestCase(unittest.TestCase):
431 MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
432 MIN = fromHex('0x1p-1022') # min normal
433 TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
434 EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
435
436 def identical(self, x, y):
437 # check that floats x and y are identical, or that both
438 # are NaNs
439 if isnan(x) or isnan(y):
440 if isnan(x) == isnan(y):
441 return
442 elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
443 return
444 self.fail('%r not identical to %r' % (x, y))
445
446 def test_ends(self):
Mark Dickinson62764562008-07-15 21:55:23 +0000447 self.identical(self.MIN, ldexp(1.0, -1022))
448 self.identical(self.TINY, ldexp(1.0, -1074))
449 self.identical(self.EPS, ldexp(1.0, -52))
450 self.identical(self.MAX, 2.*(ldexp(1.0, 1023) - ldexp(1.0, 970)))
Mark Dickinson7103aa42008-07-15 19:08:33 +0000451
452 def test_invalid_inputs(self):
453 invalid_inputs = [
454 'infi', # misspelt infinities and nans
455 '-Infinit',
456 '++inf',
457 '-+Inf',
458 '--nan',
459 '+-NaN',
460 'snan',
461 'NaNs',
462 'nna',
Mark Dickinsonb1d45852009-05-11 15:33:08 +0000463 'an',
464 'nf',
465 'nfinity',
466 'inity',
467 'iinity',
Mark Dickinson7103aa42008-07-15 19:08:33 +0000468 '0xnan',
469 '',
470 ' ',
471 'x1.0p0',
472 '0xX1.0p0',
473 '+ 0x1.0p0', # internal whitespace
474 '- 0x1.0p0',
475 '0 x1.0p0',
476 '0x 1.0p0',
477 '0x1 2.0p0',
478 '+0x1 .0p0',
479 '0x1. 0p0',
480 '-0x1.0 1p0',
481 '-0x1.0 p0',
482 '+0x1.0p +0',
483 '0x1.0p -0',
484 '0x1.0p 0',
485 '+0x1.0p+ 0',
486 '-0x1.0p- 0',
487 '++0x1.0p-0', # double signs
488 '--0x1.0p0',
489 '+-0x1.0p+0',
490 '-+0x1.0p0',
491 '0x1.0p++0',
492 '+0x1.0p+-0',
493 '-0x1.0p-+0',
494 '0x1.0p--0',
495 '0x1.0.p0',
496 '0x.p0', # no hex digits before or after point
497 '0x1,p0', # wrong decimal point character
498 '0x1pa',
499 u'0x1p\uff10', # fullwidth Unicode digits
500 u'\uff10x1p0',
501 u'0x\uff11p0',
502 u'0x1.\uff10p0',
503 '0x1p0 \n 0x2p0',
504 '0x1p0\0 0x1p0', # embedded null byte is not end of string
505 ]
506 for x in invalid_inputs:
Mark Dickinson892429b2008-08-21 20:02:24 +0000507 try:
508 result = fromHex(x)
509 except ValueError:
510 pass
511 else:
512 self.fail('Expected float.fromhex(%r) to raise ValueError; '
513 'got %r instead' % (x, result))
Mark Dickinson7103aa42008-07-15 19:08:33 +0000514
515
Mark Dickinsonb1d45852009-05-11 15:33:08 +0000516 def test_whitespace(self):
517 value_pairs = [
518 ('inf', INF),
519 ('-Infinity', -INF),
520 ('nan', NAN),
521 ('1.0', 1.0),
522 ('-0x.2', -0.125),
523 ('-0.0', -0.0)
524 ]
525 whitespace = [
526 '',
527 ' ',
528 '\t',
529 '\n',
530 '\n \t',
531 '\f',
532 '\v',
533 '\r'
534 ]
535 for inp, expected in value_pairs:
536 for lead in whitespace:
537 for trail in whitespace:
538 got = fromHex(lead + inp + trail)
539 self.identical(got, expected)
540
541
Mark Dickinson7103aa42008-07-15 19:08:33 +0000542 def test_from_hex(self):
543 MIN = self.MIN;
544 MAX = self.MAX;
545 TINY = self.TINY;
546 EPS = self.EPS;
547
548 # two spellings of infinity, with optional signs; case-insensitive
549 self.identical(fromHex('inf'), INF)
550 self.identical(fromHex('+Inf'), INF)
551 self.identical(fromHex('-INF'), -INF)
552 self.identical(fromHex('iNf'), INF)
553 self.identical(fromHex('Infinity'), INF)
554 self.identical(fromHex('+INFINITY'), INF)
555 self.identical(fromHex('-infinity'), -INF)
556 self.identical(fromHex('-iNFiNitY'), -INF)
557
558 # nans with optional sign; case insensitive
559 self.identical(fromHex('nan'), NAN)
560 self.identical(fromHex('+NaN'), NAN)
561 self.identical(fromHex('-NaN'), NAN)
562 self.identical(fromHex('-nAN'), NAN)
563
564 # variations in input format
565 self.identical(fromHex('1'), 1.0)
566 self.identical(fromHex('+1'), 1.0)
567 self.identical(fromHex('1.'), 1.0)
568 self.identical(fromHex('1.0'), 1.0)
569 self.identical(fromHex('1.0p0'), 1.0)
570 self.identical(fromHex('01'), 1.0)
571 self.identical(fromHex('01.'), 1.0)
572 self.identical(fromHex('0x1'), 1.0)
573 self.identical(fromHex('0x1.'), 1.0)
574 self.identical(fromHex('0x1.0'), 1.0)
575 self.identical(fromHex('+0x1.0'), 1.0)
576 self.identical(fromHex('0x1p0'), 1.0)
577 self.identical(fromHex('0X1p0'), 1.0)
578 self.identical(fromHex('0X1P0'), 1.0)
579 self.identical(fromHex('0x1P0'), 1.0)
580 self.identical(fromHex('0x1.p0'), 1.0)
581 self.identical(fromHex('0x1.0p0'), 1.0)
582 self.identical(fromHex('0x.1p4'), 1.0)
583 self.identical(fromHex('0x.1p04'), 1.0)
584 self.identical(fromHex('0x.1p004'), 1.0)
585 self.identical(fromHex('0x1p+0'), 1.0)
586 self.identical(fromHex('0x1P-0'), 1.0)
587 self.identical(fromHex('+0x1p0'), 1.0)
588 self.identical(fromHex('0x01p0'), 1.0)
589 self.identical(fromHex('0x1p00'), 1.0)
590 self.identical(fromHex(u'0x1p0'), 1.0)
591 self.identical(fromHex(' 0x1p0 '), 1.0)
592 self.identical(fromHex('\n 0x1p0'), 1.0)
593 self.identical(fromHex('0x1p0 \t'), 1.0)
594 self.identical(fromHex('0xap0'), 10.0)
595 self.identical(fromHex('0xAp0'), 10.0)
596 self.identical(fromHex('0xaP0'), 10.0)
597 self.identical(fromHex('0xAP0'), 10.0)
598 self.identical(fromHex('0xbep0'), 190.0)
599 self.identical(fromHex('0xBep0'), 190.0)
600 self.identical(fromHex('0xbEp0'), 190.0)
601 self.identical(fromHex('0XBE0P-4'), 190.0)
602 self.identical(fromHex('0xBEp0'), 190.0)
603 self.identical(fromHex('0xB.Ep4'), 190.0)
604 self.identical(fromHex('0x.BEp8'), 190.0)
605 self.identical(fromHex('0x.0BEp12'), 190.0)
606
607 # moving the point around
608 pi = fromHex('0x1.921fb54442d18p1')
609 self.identical(fromHex('0x.006487ed5110b46p11'), pi)
610 self.identical(fromHex('0x.00c90fdaa22168cp10'), pi)
611 self.identical(fromHex('0x.01921fb54442d18p9'), pi)
612 self.identical(fromHex('0x.03243f6a8885a3p8'), pi)
613 self.identical(fromHex('0x.06487ed5110b46p7'), pi)
614 self.identical(fromHex('0x.0c90fdaa22168cp6'), pi)
615 self.identical(fromHex('0x.1921fb54442d18p5'), pi)
616 self.identical(fromHex('0x.3243f6a8885a3p4'), pi)
617 self.identical(fromHex('0x.6487ed5110b46p3'), pi)
618 self.identical(fromHex('0x.c90fdaa22168cp2'), pi)
619 self.identical(fromHex('0x1.921fb54442d18p1'), pi)
620 self.identical(fromHex('0x3.243f6a8885a3p0'), pi)
621 self.identical(fromHex('0x6.487ed5110b46p-1'), pi)
622 self.identical(fromHex('0xc.90fdaa22168cp-2'), pi)
623 self.identical(fromHex('0x19.21fb54442d18p-3'), pi)
624 self.identical(fromHex('0x32.43f6a8885a3p-4'), pi)
625 self.identical(fromHex('0x64.87ed5110b46p-5'), pi)
626 self.identical(fromHex('0xc9.0fdaa22168cp-6'), pi)
627 self.identical(fromHex('0x192.1fb54442d18p-7'), pi)
628 self.identical(fromHex('0x324.3f6a8885a3p-8'), pi)
629 self.identical(fromHex('0x648.7ed5110b46p-9'), pi)
630 self.identical(fromHex('0xc90.fdaa22168cp-10'), pi)
631 self.identical(fromHex('0x1921.fb54442d18p-11'), pi)
632 # ...
633 self.identical(fromHex('0x1921fb54442d1.8p-47'), pi)
634 self.identical(fromHex('0x3243f6a8885a3p-48'), pi)
635 self.identical(fromHex('0x6487ed5110b46p-49'), pi)
636 self.identical(fromHex('0xc90fdaa22168cp-50'), pi)
637 self.identical(fromHex('0x1921fb54442d18p-51'), pi)
638 self.identical(fromHex('0x3243f6a8885a30p-52'), pi)
639 self.identical(fromHex('0x6487ed5110b460p-53'), pi)
640 self.identical(fromHex('0xc90fdaa22168c0p-54'), pi)
641 self.identical(fromHex('0x1921fb54442d180p-55'), pi)
642
643
644 # results that should overflow...
645 self.assertRaises(OverflowError, fromHex, '-0x1p1024')
646 self.assertRaises(OverflowError, fromHex, '0x1p+1025')
647 self.assertRaises(OverflowError, fromHex, '+0X1p1030')
648 self.assertRaises(OverflowError, fromHex, '-0x1p+1100')
649 self.assertRaises(OverflowError, fromHex, '0X1p123456789123456789')
650 self.assertRaises(OverflowError, fromHex, '+0X.8p+1025')
651 self.assertRaises(OverflowError, fromHex, '+0x0.8p1025')
652 self.assertRaises(OverflowError, fromHex, '-0x0.4p1026')
653 self.assertRaises(OverflowError, fromHex, '0X2p+1023')
654 self.assertRaises(OverflowError, fromHex, '0x2.p1023')
655 self.assertRaises(OverflowError, fromHex, '-0x2.0p+1023')
656 self.assertRaises(OverflowError, fromHex, '+0X4p+1022')
657 self.assertRaises(OverflowError, fromHex, '0x1.ffffffffffffffp+1023')
658 self.assertRaises(OverflowError, fromHex, '-0X1.fffffffffffff9p1023')
659 self.assertRaises(OverflowError, fromHex, '0X1.fffffffffffff8p1023')
660 self.assertRaises(OverflowError, fromHex, '+0x3.fffffffffffffp1022')
661 self.assertRaises(OverflowError, fromHex, '0x3fffffffffffffp+970')
662 self.assertRaises(OverflowError, fromHex, '0x10000000000000000p960')
663 self.assertRaises(OverflowError, fromHex, '-0Xffffffffffffffffp960')
664
665 # ...and those that round to +-max float
666 self.identical(fromHex('+0x1.fffffffffffffp+1023'), MAX)
667 self.identical(fromHex('-0X1.fffffffffffff7p1023'), -MAX)
668 self.identical(fromHex('0X1.fffffffffffff7fffffffffffffp1023'), MAX)
669
670 # zeros
671 self.identical(fromHex('0x0p0'), 0.0)
672 self.identical(fromHex('0x0p1000'), 0.0)
673 self.identical(fromHex('-0x0p1023'), -0.0)
674 self.identical(fromHex('0X0p1024'), 0.0)
675 self.identical(fromHex('-0x0p1025'), -0.0)
676 self.identical(fromHex('0X0p2000'), 0.0)
677 self.identical(fromHex('0x0p123456789123456789'), 0.0)
678 self.identical(fromHex('-0X0p-0'), -0.0)
679 self.identical(fromHex('-0X0p-1000'), -0.0)
680 self.identical(fromHex('0x0p-1023'), 0.0)
681 self.identical(fromHex('-0X0p-1024'), -0.0)
682 self.identical(fromHex('-0x0p-1025'), -0.0)
683 self.identical(fromHex('-0x0p-1072'), -0.0)
684 self.identical(fromHex('0X0p-1073'), 0.0)
685 self.identical(fromHex('-0x0p-1074'), -0.0)
686 self.identical(fromHex('0x0p-1075'), 0.0)
687 self.identical(fromHex('0X0p-1076'), 0.0)
688 self.identical(fromHex('-0X0p-2000'), -0.0)
689 self.identical(fromHex('-0x0p-123456789123456789'), -0.0)
690
691 # values that should underflow to 0
692 self.identical(fromHex('0X1p-1075'), 0.0)
693 self.identical(fromHex('-0X1p-1075'), -0.0)
694 self.identical(fromHex('-0x1p-123456789123456789'), -0.0)
695 self.identical(fromHex('0x1.00000000000000001p-1075'), TINY)
696 self.identical(fromHex('-0x1.1p-1075'), -TINY)
697 self.identical(fromHex('0x1.fffffffffffffffffp-1075'), TINY)
698
699 # check round-half-even is working correctly near 0 ...
700 self.identical(fromHex('0x1p-1076'), 0.0)
701 self.identical(fromHex('0X2p-1076'), 0.0)
702 self.identical(fromHex('0X3p-1076'), TINY)
703 self.identical(fromHex('0x4p-1076'), TINY)
704 self.identical(fromHex('0X5p-1076'), TINY)
705 self.identical(fromHex('0X6p-1076'), 2*TINY)
706 self.identical(fromHex('0x7p-1076'), 2*TINY)
707 self.identical(fromHex('0X8p-1076'), 2*TINY)
708 self.identical(fromHex('0X9p-1076'), 2*TINY)
709 self.identical(fromHex('0xap-1076'), 2*TINY)
710 self.identical(fromHex('0Xbp-1076'), 3*TINY)
711 self.identical(fromHex('0xcp-1076'), 3*TINY)
712 self.identical(fromHex('0Xdp-1076'), 3*TINY)
713 self.identical(fromHex('0Xep-1076'), 4*TINY)
714 self.identical(fromHex('0xfp-1076'), 4*TINY)
715 self.identical(fromHex('0x10p-1076'), 4*TINY)
716 self.identical(fromHex('-0x1p-1076'), -0.0)
717 self.identical(fromHex('-0X2p-1076'), -0.0)
718 self.identical(fromHex('-0x3p-1076'), -TINY)
719 self.identical(fromHex('-0X4p-1076'), -TINY)
720 self.identical(fromHex('-0x5p-1076'), -TINY)
721 self.identical(fromHex('-0x6p-1076'), -2*TINY)
722 self.identical(fromHex('-0X7p-1076'), -2*TINY)
723 self.identical(fromHex('-0X8p-1076'), -2*TINY)
724 self.identical(fromHex('-0X9p-1076'), -2*TINY)
725 self.identical(fromHex('-0Xap-1076'), -2*TINY)
726 self.identical(fromHex('-0xbp-1076'), -3*TINY)
727 self.identical(fromHex('-0xcp-1076'), -3*TINY)
728 self.identical(fromHex('-0Xdp-1076'), -3*TINY)
729 self.identical(fromHex('-0xep-1076'), -4*TINY)
730 self.identical(fromHex('-0Xfp-1076'), -4*TINY)
731 self.identical(fromHex('-0X10p-1076'), -4*TINY)
732
733 # ... and near MIN ...
734 self.identical(fromHex('0x0.ffffffffffffd6p-1022'), MIN-3*TINY)
735 self.identical(fromHex('0x0.ffffffffffffd8p-1022'), MIN-2*TINY)
736 self.identical(fromHex('0x0.ffffffffffffdap-1022'), MIN-2*TINY)
737 self.identical(fromHex('0x0.ffffffffffffdcp-1022'), MIN-2*TINY)
738 self.identical(fromHex('0x0.ffffffffffffdep-1022'), MIN-2*TINY)
739 self.identical(fromHex('0x0.ffffffffffffe0p-1022'), MIN-2*TINY)
740 self.identical(fromHex('0x0.ffffffffffffe2p-1022'), MIN-2*TINY)
741 self.identical(fromHex('0x0.ffffffffffffe4p-1022'), MIN-2*TINY)
742 self.identical(fromHex('0x0.ffffffffffffe6p-1022'), MIN-2*TINY)
743 self.identical(fromHex('0x0.ffffffffffffe8p-1022'), MIN-2*TINY)
744 self.identical(fromHex('0x0.ffffffffffffeap-1022'), MIN-TINY)
745 self.identical(fromHex('0x0.ffffffffffffecp-1022'), MIN-TINY)
746 self.identical(fromHex('0x0.ffffffffffffeep-1022'), MIN-TINY)
747 self.identical(fromHex('0x0.fffffffffffff0p-1022'), MIN-TINY)
748 self.identical(fromHex('0x0.fffffffffffff2p-1022'), MIN-TINY)
749 self.identical(fromHex('0x0.fffffffffffff4p-1022'), MIN-TINY)
750 self.identical(fromHex('0x0.fffffffffffff6p-1022'), MIN-TINY)
751 self.identical(fromHex('0x0.fffffffffffff8p-1022'), MIN)
752 self.identical(fromHex('0x0.fffffffffffffap-1022'), MIN)
753 self.identical(fromHex('0x0.fffffffffffffcp-1022'), MIN)
754 self.identical(fromHex('0x0.fffffffffffffep-1022'), MIN)
755 self.identical(fromHex('0x1.00000000000000p-1022'), MIN)
756 self.identical(fromHex('0x1.00000000000002p-1022'), MIN)
757 self.identical(fromHex('0x1.00000000000004p-1022'), MIN)
758 self.identical(fromHex('0x1.00000000000006p-1022'), MIN)
759 self.identical(fromHex('0x1.00000000000008p-1022'), MIN)
760 self.identical(fromHex('0x1.0000000000000ap-1022'), MIN+TINY)
761 self.identical(fromHex('0x1.0000000000000cp-1022'), MIN+TINY)
762 self.identical(fromHex('0x1.0000000000000ep-1022'), MIN+TINY)
763 self.identical(fromHex('0x1.00000000000010p-1022'), MIN+TINY)
764 self.identical(fromHex('0x1.00000000000012p-1022'), MIN+TINY)
765 self.identical(fromHex('0x1.00000000000014p-1022'), MIN+TINY)
766 self.identical(fromHex('0x1.00000000000016p-1022'), MIN+TINY)
767 self.identical(fromHex('0x1.00000000000018p-1022'), MIN+2*TINY)
768
769 # ... and near 1.0.
770 self.identical(fromHex('0x0.fffffffffffff0p0'), 1.0-EPS)
771 self.identical(fromHex('0x0.fffffffffffff1p0'), 1.0-EPS)
772 self.identical(fromHex('0X0.fffffffffffff2p0'), 1.0-EPS)
773 self.identical(fromHex('0x0.fffffffffffff3p0'), 1.0-EPS)
774 self.identical(fromHex('0X0.fffffffffffff4p0'), 1.0-EPS)
775 self.identical(fromHex('0X0.fffffffffffff5p0'), 1.0-EPS/2)
776 self.identical(fromHex('0X0.fffffffffffff6p0'), 1.0-EPS/2)
777 self.identical(fromHex('0x0.fffffffffffff7p0'), 1.0-EPS/2)
778 self.identical(fromHex('0x0.fffffffffffff8p0'), 1.0-EPS/2)
779 self.identical(fromHex('0X0.fffffffffffff9p0'), 1.0-EPS/2)
780 self.identical(fromHex('0X0.fffffffffffffap0'), 1.0-EPS/2)
781 self.identical(fromHex('0x0.fffffffffffffbp0'), 1.0-EPS/2)
782 self.identical(fromHex('0X0.fffffffffffffcp0'), 1.0)
783 self.identical(fromHex('0x0.fffffffffffffdp0'), 1.0)
784 self.identical(fromHex('0X0.fffffffffffffep0'), 1.0)
785 self.identical(fromHex('0x0.ffffffffffffffp0'), 1.0)
786 self.identical(fromHex('0X1.00000000000000p0'), 1.0)
787 self.identical(fromHex('0X1.00000000000001p0'), 1.0)
788 self.identical(fromHex('0x1.00000000000002p0'), 1.0)
789 self.identical(fromHex('0X1.00000000000003p0'), 1.0)
790 self.identical(fromHex('0x1.00000000000004p0'), 1.0)
791 self.identical(fromHex('0X1.00000000000005p0'), 1.0)
792 self.identical(fromHex('0X1.00000000000006p0'), 1.0)
793 self.identical(fromHex('0X1.00000000000007p0'), 1.0)
794 self.identical(fromHex('0x1.00000000000007ffffffffffffffffffffp0'),
795 1.0)
796 self.identical(fromHex('0x1.00000000000008p0'), 1.0)
797 self.identical(fromHex('0x1.00000000000008000000000000000001p0'),
798 1+EPS)
799 self.identical(fromHex('0X1.00000000000009p0'), 1.0+EPS)
800 self.identical(fromHex('0x1.0000000000000ap0'), 1.0+EPS)
801 self.identical(fromHex('0x1.0000000000000bp0'), 1.0+EPS)
802 self.identical(fromHex('0X1.0000000000000cp0'), 1.0+EPS)
803 self.identical(fromHex('0x1.0000000000000dp0'), 1.0+EPS)
804 self.identical(fromHex('0x1.0000000000000ep0'), 1.0+EPS)
805 self.identical(fromHex('0X1.0000000000000fp0'), 1.0+EPS)
806 self.identical(fromHex('0x1.00000000000010p0'), 1.0+EPS)
807 self.identical(fromHex('0X1.00000000000011p0'), 1.0+EPS)
808 self.identical(fromHex('0x1.00000000000012p0'), 1.0+EPS)
809 self.identical(fromHex('0X1.00000000000013p0'), 1.0+EPS)
810 self.identical(fromHex('0X1.00000000000014p0'), 1.0+EPS)
811 self.identical(fromHex('0x1.00000000000015p0'), 1.0+EPS)
812 self.identical(fromHex('0x1.00000000000016p0'), 1.0+EPS)
813 self.identical(fromHex('0X1.00000000000017p0'), 1.0+EPS)
814 self.identical(fromHex('0x1.00000000000017ffffffffffffffffffffp0'),
815 1.0+EPS)
816 self.identical(fromHex('0x1.00000000000018p0'), 1.0+2*EPS)
817 self.identical(fromHex('0X1.00000000000018000000000000000001p0'),
818 1.0+2*EPS)
819 self.identical(fromHex('0x1.00000000000019p0'), 1.0+2*EPS)
820 self.identical(fromHex('0X1.0000000000001ap0'), 1.0+2*EPS)
821 self.identical(fromHex('0X1.0000000000001bp0'), 1.0+2*EPS)
822 self.identical(fromHex('0x1.0000000000001cp0'), 1.0+2*EPS)
823 self.identical(fromHex('0x1.0000000000001dp0'), 1.0+2*EPS)
824 self.identical(fromHex('0x1.0000000000001ep0'), 1.0+2*EPS)
825 self.identical(fromHex('0X1.0000000000001fp0'), 1.0+2*EPS)
826 self.identical(fromHex('0x1.00000000000020p0'), 1.0+2*EPS)
827
828 def test_roundtrip(self):
829 def roundtrip(x):
830 return fromHex(toHex(x))
831
832 for x in [NAN, INF, self.MAX, self.MIN, self.MIN-self.TINY, self.TINY, 0.0]:
833 self.identical(x, roundtrip(x))
834 self.identical(-x, roundtrip(-x))
835
836 # fromHex(toHex(x)) should exactly recover x, for any non-NaN float x.
837 import random
838 for i in xrange(10000):
839 e = random.randrange(-1200, 1200)
840 m = random.random()
841 s = random.choice([1.0, -1.0])
842 try:
843 x = s*ldexp(m, e)
844 except OverflowError:
845 pass
846 else:
847 self.identical(x, fromHex(toHex(x)))
848
Christian Heimes6f341092008-04-18 23:13:07 +0000849
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000850def test_main():
851 test_support.run_unittest(
Amaury Forgeot d'Arcfeb8cad2008-09-06 20:53:51 +0000852 GeneralFloatCases,
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000853 FormatFunctionsTestCase,
854 UnknownFormatTestCase,
Christian Heimes284d9272007-12-10 22:28:56 +0000855 IEEEFormatTestCase,
Christian Heimes0a8143f2007-12-18 23:22:54 +0000856 ReprTestCase,
857 InfNanTest,
Mark Dickinson7103aa42008-07-15 19:08:33 +0000858 HexFloatTestCase,
Christian Heimesf15c66e2007-12-11 00:54:34 +0000859 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000860
861if __name__ == '__main__':
862 test_main()