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