blob: ab791a3a34c664dafc62081bfef4bcf74bf98183 [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
Michael W. Hudsonba283e22005-05-27 15:23:20 +00008
Christian Heimes6f341092008-04-18 23:13:07 +00009INF = float("inf")
10NAN = float("nan")
Christian Heimes0a8143f2007-12-18 23:22:54 +000011
Benjamin Peterson979395b2008-05-03 21:35:18 +000012class GeneralFloatCases(unittest.TestCase):
13
14 def test_float(self):
15 self.assertEqual(float(3.14), 3.14)
16 self.assertEqual(float(314), 314.0)
17 self.assertEqual(float(314L), 314.0)
18 self.assertEqual(float(" 3.14 "), 3.14)
19 self.assertRaises(ValueError, float, " 0x3.1 ")
20 self.assertRaises(ValueError, float, " -0x3.p-1 ")
21 self.assertRaises(ValueError, float, " +0x3.p-1 ")
22 self.assertRaises(ValueError, float, "++3.14")
23 self.assertRaises(ValueError, float, "+-3.14")
24 self.assertRaises(ValueError, float, "-+3.14")
25 self.assertRaises(ValueError, float, "--3.14")
26 if have_unicode:
27 self.assertEqual(float(unicode(" 3.14 ")), 3.14)
28 self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
29 # Implementation limitation in PyFloat_FromString()
30 self.assertRaises(ValueError, float, unicode("1"*10000))
31
32 @test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
33 def test_float_with_comma(self):
34 # set locale to something that doesn't use '.' for the decimal point
35 # float must not accept the locale specific decimal point but
36 # it still has to accept the normal python syntac
37 import locale
38 if not locale.localeconv()['decimal_point'] == ',':
39 return
40
41 self.assertEqual(float(" 3.14 "), 3.14)
42 self.assertEqual(float("+3.14 "), 3.14)
43 self.assertEqual(float("-3.14 "), -3.14)
44 self.assertEqual(float(".14 "), .14)
45 self.assertEqual(float("3. "), 3.0)
46 self.assertEqual(float("3.e3 "), 3000.0)
47 self.assertEqual(float("3.2e3 "), 3200.0)
48 self.assertEqual(float("2.5e-1 "), 0.25)
49 self.assertEqual(float("5e-1"), 0.5)
50 self.assertRaises(ValueError, float, " 3,14 ")
51 self.assertRaises(ValueError, float, " +3,14 ")
52 self.assertRaises(ValueError, float, " -3,14 ")
53 self.assertRaises(ValueError, float, " 0x3.1 ")
54 self.assertRaises(ValueError, float, " -0x3.p-1 ")
55 self.assertRaises(ValueError, float, " +0x3.p-1 ")
56 self.assertEqual(float(" 25.e-1 "), 2.5)
57 self.assertEqual(fcmp(float(" .25e-1 "), .025), 0)
58
59 def test_floatconversion(self):
60 # Make sure that calls to __float__() work properly
61 class Foo0:
62 def __float__(self):
63 return 42.
64
65 class Foo1(object):
66 def __float__(self):
67 return 42.
68
69 class Foo2(float):
70 def __float__(self):
71 return 42.
72
73 class Foo3(float):
74 def __new__(cls, value=0.):
75 return float.__new__(cls, 2*value)
76
77 def __float__(self):
78 return self
79
80 class Foo4(float):
81 def __float__(self):
82 return 42
83
84 self.assertAlmostEqual(float(Foo0()), 42.)
85 self.assertAlmostEqual(float(Foo1()), 42.)
86 self.assertAlmostEqual(float(Foo2()), 42.)
87 self.assertAlmostEqual(float(Foo3(21)), 42.)
88 self.assertRaises(TypeError, float, Foo4(42))
89
90 def test_floatasratio(self):
91 for f, ratio in [
92 (0.875, (7, 8)),
93 (-0.875, (-7, 8)),
94 (0.0, (0, 1)),
95 (11.5, (23, 2)),
96 ]:
97 self.assertEqual(f.as_integer_ratio(), ratio)
98
99 for i in range(10000):
100 f = random.random()
101 f *= 10 ** random.randint(-100, 100)
102 n, d = f.as_integer_ratio()
103 self.assertEqual(float(n).__truediv__(d), f)
104
105 R = fractions.Fraction
106 self.assertEqual(R(0, 1),
107 R(*float(0.0).as_integer_ratio()))
108 self.assertEqual(R(5, 2),
109 R(*float(2.5).as_integer_ratio()))
110 self.assertEqual(R(1, 2),
111 R(*float(0.5).as_integer_ratio()))
112 self.assertEqual(R(4728779608739021, 2251799813685248),
113 R(*float(2.1).as_integer_ratio()))
114 self.assertEqual(R(-4728779608739021, 2251799813685248),
115 R(*float(-2.1).as_integer_ratio()))
116 self.assertEqual(R(-2100, 1),
117 R(*float(-2100.0).as_integer_ratio()))
118
119 self.assertRaises(OverflowError, float('inf').as_integer_ratio)
120 self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
121 self.assertRaises(ValueError, float('nan').as_integer_ratio)
122
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000123class FormatFunctionsTestCase(unittest.TestCase):
124
125 def setUp(self):
126 self.save_formats = {'double':float.__getformat__('double'),
127 'float':float.__getformat__('float')}
128
129 def tearDown(self):
130 float.__setformat__('double', self.save_formats['double'])
131 float.__setformat__('float', self.save_formats['float'])
132
133 def test_getformat(self):
134 self.assert_(float.__getformat__('double') in
135 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
136 self.assert_(float.__getformat__('float') in
137 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
138 self.assertRaises(ValueError, float.__getformat__, 'chicken')
139 self.assertRaises(TypeError, float.__getformat__, 1)
140
141 def test_setformat(self):
142 for t in 'double', 'float':
143 float.__setformat__(t, 'unknown')
144 if self.save_formats[t] == 'IEEE, big-endian':
145 self.assertRaises(ValueError, float.__setformat__,
146 t, 'IEEE, little-endian')
147 elif self.save_formats[t] == 'IEEE, little-endian':
148 self.assertRaises(ValueError, float.__setformat__,
149 t, 'IEEE, big-endian')
150 else:
151 self.assertRaises(ValueError, float.__setformat__,
152 t, 'IEEE, big-endian')
153 self.assertRaises(ValueError, float.__setformat__,
154 t, 'IEEE, little-endian')
155 self.assertRaises(ValueError, float.__setformat__,
156 t, 'chicken')
157 self.assertRaises(ValueError, float.__setformat__,
158 'chicken', 'unknown')
159
160BE_DOUBLE_INF = '\x7f\xf0\x00\x00\x00\x00\x00\x00'
161LE_DOUBLE_INF = ''.join(reversed(BE_DOUBLE_INF))
162BE_DOUBLE_NAN = '\x7f\xf8\x00\x00\x00\x00\x00\x00'
163LE_DOUBLE_NAN = ''.join(reversed(BE_DOUBLE_NAN))
164
165BE_FLOAT_INF = '\x7f\x80\x00\x00'
166LE_FLOAT_INF = ''.join(reversed(BE_FLOAT_INF))
167BE_FLOAT_NAN = '\x7f\xc0\x00\x00'
168LE_FLOAT_NAN = ''.join(reversed(BE_FLOAT_NAN))
169
170# on non-IEEE platforms, attempting to unpack a bit pattern
171# representing an infinity or a NaN should raise an exception.
172
173class UnknownFormatTestCase(unittest.TestCase):
174 def setUp(self):
175 self.save_formats = {'double':float.__getformat__('double'),
176 'float':float.__getformat__('float')}
177 float.__setformat__('double', 'unknown')
178 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000179
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000180 def tearDown(self):
181 float.__setformat__('double', self.save_formats['double'])
182 float.__setformat__('float', self.save_formats['float'])
183
184 def test_double_specials_dont_unpack(self):
185 for fmt, data in [('>d', BE_DOUBLE_INF),
186 ('>d', BE_DOUBLE_NAN),
187 ('<d', LE_DOUBLE_INF),
188 ('<d', LE_DOUBLE_NAN)]:
189 self.assertRaises(ValueError, struct.unpack, fmt, data)
190
191 def test_float_specials_dont_unpack(self):
192 for fmt, data in [('>f', BE_FLOAT_INF),
193 ('>f', BE_FLOAT_NAN),
194 ('<f', LE_FLOAT_INF),
195 ('<f', LE_FLOAT_NAN)]:
196 self.assertRaises(ValueError, struct.unpack, fmt, data)
197
198
199# on an IEEE platform, all we guarantee is that bit patterns
200# representing infinities or NaNs do not raise an exception; all else
201# is accident (today).
Alex Martellid8672aa2007-08-22 21:14:17 +0000202# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000203
204class IEEEFormatTestCase(unittest.TestCase):
205 if float.__getformat__("double").startswith("IEEE"):
206 def test_double_specials_do_unpack(self):
207 for fmt, data in [('>d', BE_DOUBLE_INF),
208 ('>d', BE_DOUBLE_NAN),
209 ('<d', LE_DOUBLE_INF),
210 ('<d', LE_DOUBLE_NAN)]:
211 struct.unpack(fmt, data)
212
213 if float.__getformat__("float").startswith("IEEE"):
214 def test_float_specials_do_unpack(self):
215 for fmt, data in [('>f', BE_FLOAT_INF),
216 ('>f', BE_FLOAT_NAN),
217 ('<f', LE_FLOAT_INF),
218 ('<f', LE_FLOAT_NAN)]:
219 struct.unpack(fmt, data)
220
Alex Martellid8672aa2007-08-22 21:14:17 +0000221 if float.__getformat__("double").startswith("IEEE"):
222 def test_negative_zero(self):
223 import math
224 def pos_pos():
225 return 0.0, math.atan2(0.0, -1)
226 def pos_neg():
227 return 0.0, math.atan2(-0.0, -1)
228 def neg_pos():
229 return -0.0, math.atan2(0.0, -1)
230 def neg_neg():
231 return -0.0, math.atan2(-0.0, -1)
232 self.assertEquals(pos_pos(), neg_pos())
233 self.assertEquals(pos_neg(), neg_neg())
234
Guido van Rossum3b835492008-01-05 00:59:59 +0000235 if float.__getformat__("double").startswith("IEEE"):
236 def test_underflow_sign(self):
237 import math
238 # check that -1e-1000 gives -0.0, not 0.0
239 self.assertEquals(math.atan2(-1e-1000, -1), math.atan2(-0.0, -1))
240 self.assertEquals(math.atan2(float('-1e-1000'), -1),
241 math.atan2(-0.0, -1))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000242
Christian Heimes284d9272007-12-10 22:28:56 +0000243class ReprTestCase(unittest.TestCase):
244 def test_repr(self):
245 floats_file = open(os.path.join(os.path.split(__file__)[0],
246 'floating_points.txt'))
247 for line in floats_file:
248 line = line.strip()
249 if not line or line.startswith('#'):
250 continue
251 v = eval(line)
252 self.assertEqual(v, eval(repr(v)))
253 floats_file.close()
254
Christian Heimes0a8143f2007-12-18 23:22:54 +0000255# Beginning with Python 2.6 float has cross platform compatible
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000256# ways to create and represent inf and nan
Christian Heimes0a8143f2007-12-18 23:22:54 +0000257class InfNanTest(unittest.TestCase):
258 def test_inf_from_str(self):
259 self.assert_(isinf(float("inf")))
260 self.assert_(isinf(float("+inf")))
261 self.assert_(isinf(float("-inf")))
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000262 self.assert_(isinf(float("infinity")))
263 self.assert_(isinf(float("+infinity")))
264 self.assert_(isinf(float("-infinity")))
Christian Heimes0a8143f2007-12-18 23:22:54 +0000265
266 self.assertEqual(repr(float("inf")), "inf")
267 self.assertEqual(repr(float("+inf")), "inf")
268 self.assertEqual(repr(float("-inf")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000269 self.assertEqual(repr(float("infinity")), "inf")
270 self.assertEqual(repr(float("+infinity")), "inf")
271 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000272
273 self.assertEqual(repr(float("INF")), "inf")
274 self.assertEqual(repr(float("+Inf")), "inf")
275 self.assertEqual(repr(float("-iNF")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000276 self.assertEqual(repr(float("Infinity")), "inf")
277 self.assertEqual(repr(float("+iNfInItY")), "inf")
278 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000279
280 self.assertEqual(str(float("inf")), "inf")
281 self.assertEqual(str(float("+inf")), "inf")
282 self.assertEqual(str(float("-inf")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000283 self.assertEqual(str(float("infinity")), "inf")
284 self.assertEqual(str(float("+infinity")), "inf")
285 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000286
287 self.assertRaises(ValueError, float, "info")
288 self.assertRaises(ValueError, float, "+info")
289 self.assertRaises(ValueError, float, "-info")
290 self.assertRaises(ValueError, float, "in")
291 self.assertRaises(ValueError, float, "+in")
292 self.assertRaises(ValueError, float, "-in")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000293 self.assertRaises(ValueError, float, "infinit")
294 self.assertRaises(ValueError, float, "+Infin")
295 self.assertRaises(ValueError, float, "-INFI")
296 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000297
298 def test_inf_as_str(self):
299 self.assertEqual(repr(1e300 * 1e300), "inf")
300 self.assertEqual(repr(-1e300 * 1e300), "-inf")
301
302 self.assertEqual(str(1e300 * 1e300), "inf")
303 self.assertEqual(str(-1e300 * 1e300), "-inf")
304
305 def test_nan_from_str(self):
306 self.assert_(isnan(float("nan")))
307 self.assert_(isnan(float("+nan")))
308 self.assert_(isnan(float("-nan")))
309
310 self.assertEqual(repr(float("nan")), "nan")
311 self.assertEqual(repr(float("+nan")), "nan")
312 self.assertEqual(repr(float("-nan")), "nan")
313
314 self.assertEqual(repr(float("NAN")), "nan")
315 self.assertEqual(repr(float("+NAn")), "nan")
316 self.assertEqual(repr(float("-NaN")), "nan")
317
318 self.assertEqual(str(float("nan")), "nan")
319 self.assertEqual(str(float("+nan")), "nan")
320 self.assertEqual(str(float("-nan")), "nan")
321
322 self.assertRaises(ValueError, float, "nana")
323 self.assertRaises(ValueError, float, "+nana")
324 self.assertRaises(ValueError, float, "-nana")
325 self.assertRaises(ValueError, float, "na")
326 self.assertRaises(ValueError, float, "+na")
327 self.assertRaises(ValueError, float, "-na")
328
329 def test_nan_as_str(self):
330 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
331 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
332
333 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
334 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes284d9272007-12-10 22:28:56 +0000335
Christian Heimes6f341092008-04-18 23:13:07 +0000336 def notest_float_nan(self):
337 self.assert_(NAN.is_nan())
338 self.failIf(INF.is_nan())
339 self.failIf((0.).is_nan())
340
341 def notest_float_inf(self):
342 self.assert_(INF.is_inf())
343 self.failIf(NAN.is_inf())
344 self.failIf((0.).is_inf())
345
Mark Dickinson7103aa42008-07-15 19:08:33 +0000346fromHex = float.fromhex
347toHex = float.hex
348class HexFloatTestCase(unittest.TestCase):
349 MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
350 MIN = fromHex('0x1p-1022') # min normal
351 TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
352 EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
353
354 def identical(self, x, y):
355 # check that floats x and y are identical, or that both
356 # are NaNs
357 if isnan(x) or isnan(y):
358 if isnan(x) == isnan(y):
359 return
360 elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
361 return
362 self.fail('%r not identical to %r' % (x, y))
363
364 def test_ends(self):
Mark Dickinson62764562008-07-15 21:55:23 +0000365 self.identical(self.MIN, ldexp(1.0, -1022))
366 self.identical(self.TINY, ldexp(1.0, -1074))
367 self.identical(self.EPS, ldexp(1.0, -52))
368 self.identical(self.MAX, 2.*(ldexp(1.0, 1023) - ldexp(1.0, 970)))
Mark Dickinson7103aa42008-07-15 19:08:33 +0000369
370 def test_invalid_inputs(self):
371 invalid_inputs = [
372 'infi', # misspelt infinities and nans
373 '-Infinit',
374 '++inf',
375 '-+Inf',
376 '--nan',
377 '+-NaN',
378 'snan',
379 'NaNs',
380 'nna',
381 '0xnan',
382 '',
383 ' ',
384 'x1.0p0',
385 '0xX1.0p0',
386 '+ 0x1.0p0', # internal whitespace
387 '- 0x1.0p0',
388 '0 x1.0p0',
389 '0x 1.0p0',
390 '0x1 2.0p0',
391 '+0x1 .0p0',
392 '0x1. 0p0',
393 '-0x1.0 1p0',
394 '-0x1.0 p0',
395 '+0x1.0p +0',
396 '0x1.0p -0',
397 '0x1.0p 0',
398 '+0x1.0p+ 0',
399 '-0x1.0p- 0',
400 '++0x1.0p-0', # double signs
401 '--0x1.0p0',
402 '+-0x1.0p+0',
403 '-+0x1.0p0',
404 '0x1.0p++0',
405 '+0x1.0p+-0',
406 '-0x1.0p-+0',
407 '0x1.0p--0',
408 '0x1.0.p0',
409 '0x.p0', # no hex digits before or after point
410 '0x1,p0', # wrong decimal point character
411 '0x1pa',
412 u'0x1p\uff10', # fullwidth Unicode digits
413 u'\uff10x1p0',
414 u'0x\uff11p0',
415 u'0x1.\uff10p0',
416 '0x1p0 \n 0x2p0',
417 '0x1p0\0 0x1p0', # embedded null byte is not end of string
418 ]
419 for x in invalid_inputs:
Mark Dickinson892429b2008-08-21 20:02:24 +0000420 try:
421 result = fromHex(x)
422 except ValueError:
423 pass
424 else:
425 self.fail('Expected float.fromhex(%r) to raise ValueError; '
426 'got %r instead' % (x, result))
Mark Dickinson7103aa42008-07-15 19:08:33 +0000427
428
429 def test_from_hex(self):
430 MIN = self.MIN;
431 MAX = self.MAX;
432 TINY = self.TINY;
433 EPS = self.EPS;
434
435 # two spellings of infinity, with optional signs; case-insensitive
436 self.identical(fromHex('inf'), INF)
437 self.identical(fromHex('+Inf'), INF)
438 self.identical(fromHex('-INF'), -INF)
439 self.identical(fromHex('iNf'), INF)
440 self.identical(fromHex('Infinity'), INF)
441 self.identical(fromHex('+INFINITY'), INF)
442 self.identical(fromHex('-infinity'), -INF)
443 self.identical(fromHex('-iNFiNitY'), -INF)
444
445 # nans with optional sign; case insensitive
446 self.identical(fromHex('nan'), NAN)
447 self.identical(fromHex('+NaN'), NAN)
448 self.identical(fromHex('-NaN'), NAN)
449 self.identical(fromHex('-nAN'), NAN)
450
451 # variations in input format
452 self.identical(fromHex('1'), 1.0)
453 self.identical(fromHex('+1'), 1.0)
454 self.identical(fromHex('1.'), 1.0)
455 self.identical(fromHex('1.0'), 1.0)
456 self.identical(fromHex('1.0p0'), 1.0)
457 self.identical(fromHex('01'), 1.0)
458 self.identical(fromHex('01.'), 1.0)
459 self.identical(fromHex('0x1'), 1.0)
460 self.identical(fromHex('0x1.'), 1.0)
461 self.identical(fromHex('0x1.0'), 1.0)
462 self.identical(fromHex('+0x1.0'), 1.0)
463 self.identical(fromHex('0x1p0'), 1.0)
464 self.identical(fromHex('0X1p0'), 1.0)
465 self.identical(fromHex('0X1P0'), 1.0)
466 self.identical(fromHex('0x1P0'), 1.0)
467 self.identical(fromHex('0x1.p0'), 1.0)
468 self.identical(fromHex('0x1.0p0'), 1.0)
469 self.identical(fromHex('0x.1p4'), 1.0)
470 self.identical(fromHex('0x.1p04'), 1.0)
471 self.identical(fromHex('0x.1p004'), 1.0)
472 self.identical(fromHex('0x1p+0'), 1.0)
473 self.identical(fromHex('0x1P-0'), 1.0)
474 self.identical(fromHex('+0x1p0'), 1.0)
475 self.identical(fromHex('0x01p0'), 1.0)
476 self.identical(fromHex('0x1p00'), 1.0)
477 self.identical(fromHex(u'0x1p0'), 1.0)
478 self.identical(fromHex(' 0x1p0 '), 1.0)
479 self.identical(fromHex('\n 0x1p0'), 1.0)
480 self.identical(fromHex('0x1p0 \t'), 1.0)
481 self.identical(fromHex('0xap0'), 10.0)
482 self.identical(fromHex('0xAp0'), 10.0)
483 self.identical(fromHex('0xaP0'), 10.0)
484 self.identical(fromHex('0xAP0'), 10.0)
485 self.identical(fromHex('0xbep0'), 190.0)
486 self.identical(fromHex('0xBep0'), 190.0)
487 self.identical(fromHex('0xbEp0'), 190.0)
488 self.identical(fromHex('0XBE0P-4'), 190.0)
489 self.identical(fromHex('0xBEp0'), 190.0)
490 self.identical(fromHex('0xB.Ep4'), 190.0)
491 self.identical(fromHex('0x.BEp8'), 190.0)
492 self.identical(fromHex('0x.0BEp12'), 190.0)
493
494 # moving the point around
495 pi = fromHex('0x1.921fb54442d18p1')
496 self.identical(fromHex('0x.006487ed5110b46p11'), pi)
497 self.identical(fromHex('0x.00c90fdaa22168cp10'), pi)
498 self.identical(fromHex('0x.01921fb54442d18p9'), pi)
499 self.identical(fromHex('0x.03243f6a8885a3p8'), pi)
500 self.identical(fromHex('0x.06487ed5110b46p7'), pi)
501 self.identical(fromHex('0x.0c90fdaa22168cp6'), pi)
502 self.identical(fromHex('0x.1921fb54442d18p5'), pi)
503 self.identical(fromHex('0x.3243f6a8885a3p4'), pi)
504 self.identical(fromHex('0x.6487ed5110b46p3'), pi)
505 self.identical(fromHex('0x.c90fdaa22168cp2'), pi)
506 self.identical(fromHex('0x1.921fb54442d18p1'), pi)
507 self.identical(fromHex('0x3.243f6a8885a3p0'), pi)
508 self.identical(fromHex('0x6.487ed5110b46p-1'), pi)
509 self.identical(fromHex('0xc.90fdaa22168cp-2'), pi)
510 self.identical(fromHex('0x19.21fb54442d18p-3'), pi)
511 self.identical(fromHex('0x32.43f6a8885a3p-4'), pi)
512 self.identical(fromHex('0x64.87ed5110b46p-5'), pi)
513 self.identical(fromHex('0xc9.0fdaa22168cp-6'), pi)
514 self.identical(fromHex('0x192.1fb54442d18p-7'), pi)
515 self.identical(fromHex('0x324.3f6a8885a3p-8'), pi)
516 self.identical(fromHex('0x648.7ed5110b46p-9'), pi)
517 self.identical(fromHex('0xc90.fdaa22168cp-10'), pi)
518 self.identical(fromHex('0x1921.fb54442d18p-11'), pi)
519 # ...
520 self.identical(fromHex('0x1921fb54442d1.8p-47'), pi)
521 self.identical(fromHex('0x3243f6a8885a3p-48'), pi)
522 self.identical(fromHex('0x6487ed5110b46p-49'), pi)
523 self.identical(fromHex('0xc90fdaa22168cp-50'), pi)
524 self.identical(fromHex('0x1921fb54442d18p-51'), pi)
525 self.identical(fromHex('0x3243f6a8885a30p-52'), pi)
526 self.identical(fromHex('0x6487ed5110b460p-53'), pi)
527 self.identical(fromHex('0xc90fdaa22168c0p-54'), pi)
528 self.identical(fromHex('0x1921fb54442d180p-55'), pi)
529
530
531 # results that should overflow...
532 self.assertRaises(OverflowError, fromHex, '-0x1p1024')
533 self.assertRaises(OverflowError, fromHex, '0x1p+1025')
534 self.assertRaises(OverflowError, fromHex, '+0X1p1030')
535 self.assertRaises(OverflowError, fromHex, '-0x1p+1100')
536 self.assertRaises(OverflowError, fromHex, '0X1p123456789123456789')
537 self.assertRaises(OverflowError, fromHex, '+0X.8p+1025')
538 self.assertRaises(OverflowError, fromHex, '+0x0.8p1025')
539 self.assertRaises(OverflowError, fromHex, '-0x0.4p1026')
540 self.assertRaises(OverflowError, fromHex, '0X2p+1023')
541 self.assertRaises(OverflowError, fromHex, '0x2.p1023')
542 self.assertRaises(OverflowError, fromHex, '-0x2.0p+1023')
543 self.assertRaises(OverflowError, fromHex, '+0X4p+1022')
544 self.assertRaises(OverflowError, fromHex, '0x1.ffffffffffffffp+1023')
545 self.assertRaises(OverflowError, fromHex, '-0X1.fffffffffffff9p1023')
546 self.assertRaises(OverflowError, fromHex, '0X1.fffffffffffff8p1023')
547 self.assertRaises(OverflowError, fromHex, '+0x3.fffffffffffffp1022')
548 self.assertRaises(OverflowError, fromHex, '0x3fffffffffffffp+970')
549 self.assertRaises(OverflowError, fromHex, '0x10000000000000000p960')
550 self.assertRaises(OverflowError, fromHex, '-0Xffffffffffffffffp960')
551
552 # ...and those that round to +-max float
553 self.identical(fromHex('+0x1.fffffffffffffp+1023'), MAX)
554 self.identical(fromHex('-0X1.fffffffffffff7p1023'), -MAX)
555 self.identical(fromHex('0X1.fffffffffffff7fffffffffffffp1023'), MAX)
556
557 # zeros
558 self.identical(fromHex('0x0p0'), 0.0)
559 self.identical(fromHex('0x0p1000'), 0.0)
560 self.identical(fromHex('-0x0p1023'), -0.0)
561 self.identical(fromHex('0X0p1024'), 0.0)
562 self.identical(fromHex('-0x0p1025'), -0.0)
563 self.identical(fromHex('0X0p2000'), 0.0)
564 self.identical(fromHex('0x0p123456789123456789'), 0.0)
565 self.identical(fromHex('-0X0p-0'), -0.0)
566 self.identical(fromHex('-0X0p-1000'), -0.0)
567 self.identical(fromHex('0x0p-1023'), 0.0)
568 self.identical(fromHex('-0X0p-1024'), -0.0)
569 self.identical(fromHex('-0x0p-1025'), -0.0)
570 self.identical(fromHex('-0x0p-1072'), -0.0)
571 self.identical(fromHex('0X0p-1073'), 0.0)
572 self.identical(fromHex('-0x0p-1074'), -0.0)
573 self.identical(fromHex('0x0p-1075'), 0.0)
574 self.identical(fromHex('0X0p-1076'), 0.0)
575 self.identical(fromHex('-0X0p-2000'), -0.0)
576 self.identical(fromHex('-0x0p-123456789123456789'), -0.0)
577
578 # values that should underflow to 0
579 self.identical(fromHex('0X1p-1075'), 0.0)
580 self.identical(fromHex('-0X1p-1075'), -0.0)
581 self.identical(fromHex('-0x1p-123456789123456789'), -0.0)
582 self.identical(fromHex('0x1.00000000000000001p-1075'), TINY)
583 self.identical(fromHex('-0x1.1p-1075'), -TINY)
584 self.identical(fromHex('0x1.fffffffffffffffffp-1075'), TINY)
585
586 # check round-half-even is working correctly near 0 ...
587 self.identical(fromHex('0x1p-1076'), 0.0)
588 self.identical(fromHex('0X2p-1076'), 0.0)
589 self.identical(fromHex('0X3p-1076'), TINY)
590 self.identical(fromHex('0x4p-1076'), TINY)
591 self.identical(fromHex('0X5p-1076'), TINY)
592 self.identical(fromHex('0X6p-1076'), 2*TINY)
593 self.identical(fromHex('0x7p-1076'), 2*TINY)
594 self.identical(fromHex('0X8p-1076'), 2*TINY)
595 self.identical(fromHex('0X9p-1076'), 2*TINY)
596 self.identical(fromHex('0xap-1076'), 2*TINY)
597 self.identical(fromHex('0Xbp-1076'), 3*TINY)
598 self.identical(fromHex('0xcp-1076'), 3*TINY)
599 self.identical(fromHex('0Xdp-1076'), 3*TINY)
600 self.identical(fromHex('0Xep-1076'), 4*TINY)
601 self.identical(fromHex('0xfp-1076'), 4*TINY)
602 self.identical(fromHex('0x10p-1076'), 4*TINY)
603 self.identical(fromHex('-0x1p-1076'), -0.0)
604 self.identical(fromHex('-0X2p-1076'), -0.0)
605 self.identical(fromHex('-0x3p-1076'), -TINY)
606 self.identical(fromHex('-0X4p-1076'), -TINY)
607 self.identical(fromHex('-0x5p-1076'), -TINY)
608 self.identical(fromHex('-0x6p-1076'), -2*TINY)
609 self.identical(fromHex('-0X7p-1076'), -2*TINY)
610 self.identical(fromHex('-0X8p-1076'), -2*TINY)
611 self.identical(fromHex('-0X9p-1076'), -2*TINY)
612 self.identical(fromHex('-0Xap-1076'), -2*TINY)
613 self.identical(fromHex('-0xbp-1076'), -3*TINY)
614 self.identical(fromHex('-0xcp-1076'), -3*TINY)
615 self.identical(fromHex('-0Xdp-1076'), -3*TINY)
616 self.identical(fromHex('-0xep-1076'), -4*TINY)
617 self.identical(fromHex('-0Xfp-1076'), -4*TINY)
618 self.identical(fromHex('-0X10p-1076'), -4*TINY)
619
620 # ... and near MIN ...
621 self.identical(fromHex('0x0.ffffffffffffd6p-1022'), MIN-3*TINY)
622 self.identical(fromHex('0x0.ffffffffffffd8p-1022'), MIN-2*TINY)
623 self.identical(fromHex('0x0.ffffffffffffdap-1022'), MIN-2*TINY)
624 self.identical(fromHex('0x0.ffffffffffffdcp-1022'), MIN-2*TINY)
625 self.identical(fromHex('0x0.ffffffffffffdep-1022'), MIN-2*TINY)
626 self.identical(fromHex('0x0.ffffffffffffe0p-1022'), MIN-2*TINY)
627 self.identical(fromHex('0x0.ffffffffffffe2p-1022'), MIN-2*TINY)
628 self.identical(fromHex('0x0.ffffffffffffe4p-1022'), MIN-2*TINY)
629 self.identical(fromHex('0x0.ffffffffffffe6p-1022'), MIN-2*TINY)
630 self.identical(fromHex('0x0.ffffffffffffe8p-1022'), MIN-2*TINY)
631 self.identical(fromHex('0x0.ffffffffffffeap-1022'), MIN-TINY)
632 self.identical(fromHex('0x0.ffffffffffffecp-1022'), MIN-TINY)
633 self.identical(fromHex('0x0.ffffffffffffeep-1022'), MIN-TINY)
634 self.identical(fromHex('0x0.fffffffffffff0p-1022'), MIN-TINY)
635 self.identical(fromHex('0x0.fffffffffffff2p-1022'), MIN-TINY)
636 self.identical(fromHex('0x0.fffffffffffff4p-1022'), MIN-TINY)
637 self.identical(fromHex('0x0.fffffffffffff6p-1022'), MIN-TINY)
638 self.identical(fromHex('0x0.fffffffffffff8p-1022'), MIN)
639 self.identical(fromHex('0x0.fffffffffffffap-1022'), MIN)
640 self.identical(fromHex('0x0.fffffffffffffcp-1022'), MIN)
641 self.identical(fromHex('0x0.fffffffffffffep-1022'), MIN)
642 self.identical(fromHex('0x1.00000000000000p-1022'), MIN)
643 self.identical(fromHex('0x1.00000000000002p-1022'), MIN)
644 self.identical(fromHex('0x1.00000000000004p-1022'), MIN)
645 self.identical(fromHex('0x1.00000000000006p-1022'), MIN)
646 self.identical(fromHex('0x1.00000000000008p-1022'), MIN)
647 self.identical(fromHex('0x1.0000000000000ap-1022'), MIN+TINY)
648 self.identical(fromHex('0x1.0000000000000cp-1022'), MIN+TINY)
649 self.identical(fromHex('0x1.0000000000000ep-1022'), MIN+TINY)
650 self.identical(fromHex('0x1.00000000000010p-1022'), MIN+TINY)
651 self.identical(fromHex('0x1.00000000000012p-1022'), MIN+TINY)
652 self.identical(fromHex('0x1.00000000000014p-1022'), MIN+TINY)
653 self.identical(fromHex('0x1.00000000000016p-1022'), MIN+TINY)
654 self.identical(fromHex('0x1.00000000000018p-1022'), MIN+2*TINY)
655
656 # ... and near 1.0.
657 self.identical(fromHex('0x0.fffffffffffff0p0'), 1.0-EPS)
658 self.identical(fromHex('0x0.fffffffffffff1p0'), 1.0-EPS)
659 self.identical(fromHex('0X0.fffffffffffff2p0'), 1.0-EPS)
660 self.identical(fromHex('0x0.fffffffffffff3p0'), 1.0-EPS)
661 self.identical(fromHex('0X0.fffffffffffff4p0'), 1.0-EPS)
662 self.identical(fromHex('0X0.fffffffffffff5p0'), 1.0-EPS/2)
663 self.identical(fromHex('0X0.fffffffffffff6p0'), 1.0-EPS/2)
664 self.identical(fromHex('0x0.fffffffffffff7p0'), 1.0-EPS/2)
665 self.identical(fromHex('0x0.fffffffffffff8p0'), 1.0-EPS/2)
666 self.identical(fromHex('0X0.fffffffffffff9p0'), 1.0-EPS/2)
667 self.identical(fromHex('0X0.fffffffffffffap0'), 1.0-EPS/2)
668 self.identical(fromHex('0x0.fffffffffffffbp0'), 1.0-EPS/2)
669 self.identical(fromHex('0X0.fffffffffffffcp0'), 1.0)
670 self.identical(fromHex('0x0.fffffffffffffdp0'), 1.0)
671 self.identical(fromHex('0X0.fffffffffffffep0'), 1.0)
672 self.identical(fromHex('0x0.ffffffffffffffp0'), 1.0)
673 self.identical(fromHex('0X1.00000000000000p0'), 1.0)
674 self.identical(fromHex('0X1.00000000000001p0'), 1.0)
675 self.identical(fromHex('0x1.00000000000002p0'), 1.0)
676 self.identical(fromHex('0X1.00000000000003p0'), 1.0)
677 self.identical(fromHex('0x1.00000000000004p0'), 1.0)
678 self.identical(fromHex('0X1.00000000000005p0'), 1.0)
679 self.identical(fromHex('0X1.00000000000006p0'), 1.0)
680 self.identical(fromHex('0X1.00000000000007p0'), 1.0)
681 self.identical(fromHex('0x1.00000000000007ffffffffffffffffffffp0'),
682 1.0)
683 self.identical(fromHex('0x1.00000000000008p0'), 1.0)
684 self.identical(fromHex('0x1.00000000000008000000000000000001p0'),
685 1+EPS)
686 self.identical(fromHex('0X1.00000000000009p0'), 1.0+EPS)
687 self.identical(fromHex('0x1.0000000000000ap0'), 1.0+EPS)
688 self.identical(fromHex('0x1.0000000000000bp0'), 1.0+EPS)
689 self.identical(fromHex('0X1.0000000000000cp0'), 1.0+EPS)
690 self.identical(fromHex('0x1.0000000000000dp0'), 1.0+EPS)
691 self.identical(fromHex('0x1.0000000000000ep0'), 1.0+EPS)
692 self.identical(fromHex('0X1.0000000000000fp0'), 1.0+EPS)
693 self.identical(fromHex('0x1.00000000000010p0'), 1.0+EPS)
694 self.identical(fromHex('0X1.00000000000011p0'), 1.0+EPS)
695 self.identical(fromHex('0x1.00000000000012p0'), 1.0+EPS)
696 self.identical(fromHex('0X1.00000000000013p0'), 1.0+EPS)
697 self.identical(fromHex('0X1.00000000000014p0'), 1.0+EPS)
698 self.identical(fromHex('0x1.00000000000015p0'), 1.0+EPS)
699 self.identical(fromHex('0x1.00000000000016p0'), 1.0+EPS)
700 self.identical(fromHex('0X1.00000000000017p0'), 1.0+EPS)
701 self.identical(fromHex('0x1.00000000000017ffffffffffffffffffffp0'),
702 1.0+EPS)
703 self.identical(fromHex('0x1.00000000000018p0'), 1.0+2*EPS)
704 self.identical(fromHex('0X1.00000000000018000000000000000001p0'),
705 1.0+2*EPS)
706 self.identical(fromHex('0x1.00000000000019p0'), 1.0+2*EPS)
707 self.identical(fromHex('0X1.0000000000001ap0'), 1.0+2*EPS)
708 self.identical(fromHex('0X1.0000000000001bp0'), 1.0+2*EPS)
709 self.identical(fromHex('0x1.0000000000001cp0'), 1.0+2*EPS)
710 self.identical(fromHex('0x1.0000000000001dp0'), 1.0+2*EPS)
711 self.identical(fromHex('0x1.0000000000001ep0'), 1.0+2*EPS)
712 self.identical(fromHex('0X1.0000000000001fp0'), 1.0+2*EPS)
713 self.identical(fromHex('0x1.00000000000020p0'), 1.0+2*EPS)
714
715 def test_roundtrip(self):
716 def roundtrip(x):
717 return fromHex(toHex(x))
718
719 for x in [NAN, INF, self.MAX, self.MIN, self.MIN-self.TINY, self.TINY, 0.0]:
720 self.identical(x, roundtrip(x))
721 self.identical(-x, roundtrip(-x))
722
723 # fromHex(toHex(x)) should exactly recover x, for any non-NaN float x.
724 import random
725 for i in xrange(10000):
726 e = random.randrange(-1200, 1200)
727 m = random.random()
728 s = random.choice([1.0, -1.0])
729 try:
730 x = s*ldexp(m, e)
731 except OverflowError:
732 pass
733 else:
734 self.identical(x, fromHex(toHex(x)))
735
Christian Heimes6f341092008-04-18 23:13:07 +0000736
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000737def test_main():
738 test_support.run_unittest(
739 FormatFunctionsTestCase,
740 UnknownFormatTestCase,
Christian Heimes284d9272007-12-10 22:28:56 +0000741 IEEEFormatTestCase,
Christian Heimes0a8143f2007-12-18 23:22:54 +0000742 ReprTestCase,
743 InfNanTest,
Mark Dickinson7103aa42008-07-15 19:08:33 +0000744 HexFloatTestCase,
Christian Heimesf15c66e2007-12-11 00:54:34 +0000745 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000746
747if __name__ == '__main__':
748 test_main()