blob: 123a69d404d3eb190a09b5fa88bfd27e91c8b6ee [file] [log] [blame]
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001
2import unittest, struct
Christian Heimes827b35c2007-12-10 22:19:17 +00003import os
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Christian Heimes53876d92008-04-19 00:31:39 +00005import math
Mark Dickinson65fe25e2008-07-16 11:30:51 +00006from math import isinf, isnan, copysign, ldexp
Christian Heimes53876d92008-04-19 00:31:39 +00007import operator
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +00008import random, fractions
Michael W. Hudsonba283e22005-05-27 15:23:20 +00009
Christian Heimes53876d92008-04-19 00:31:39 +000010INF = float("inf")
11NAN = float("nan")
Christian Heimes99170a52007-12-19 02:07:34 +000012
Christian Heimes81ee3ef2008-05-04 22:42:01 +000013class GeneralFloatCases(unittest.TestCase):
14
15 def test_float(self):
16 self.assertEqual(float(3.14), 3.14)
17 self.assertEqual(float(314), 314.0)
18 self.assertEqual(float(" 3.14 "), 3.14)
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +000019 self.assertEqual(float(b" 3.14 "), 3.14)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000020 self.assertRaises(ValueError, float, " 0x3.1 ")
21 self.assertRaises(ValueError, float, " -0x3.p-1 ")
22 self.assertRaises(ValueError, float, " +0x3.p-1 ")
23 self.assertRaises(ValueError, float, "++3.14")
24 self.assertRaises(ValueError, float, "+-3.14")
25 self.assertRaises(ValueError, float, "-+3.14")
26 self.assertRaises(ValueError, float, "--3.14")
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +000027 self.assertEqual(float(b" \u0663.\u0661\u0664 ".decode('raw-unicode-escape')), 3.14)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000028
Benjamin Petersonee8712c2008-05-20 21:35:26 +000029 @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
Christian Heimes81ee3ef2008-05-04 22:42:01 +000030 def test_float_with_comma(self):
31 # set locale to something that doesn't use '.' for the decimal point
32 # float must not accept the locale specific decimal point but
33 # it still has to accept the normal python syntac
34 import locale
35 if not locale.localeconv()['decimal_point'] == ',':
36 return
37
38 self.assertEqual(float(" 3.14 "), 3.14)
39 self.assertEqual(float("+3.14 "), 3.14)
40 self.assertEqual(float("-3.14 "), -3.14)
41 self.assertEqual(float(".14 "), .14)
42 self.assertEqual(float("3. "), 3.0)
43 self.assertEqual(float("3.e3 "), 3000.0)
44 self.assertEqual(float("3.2e3 "), 3200.0)
45 self.assertEqual(float("2.5e-1 "), 0.25)
46 self.assertEqual(float("5e-1"), 0.5)
47 self.assertRaises(ValueError, float, " 3,14 ")
48 self.assertRaises(ValueError, float, " +3,14 ")
49 self.assertRaises(ValueError, float, " -3,14 ")
50 self.assertRaises(ValueError, float, " 0x3.1 ")
51 self.assertRaises(ValueError, float, " -0x3.p-1 ")
52 self.assertRaises(ValueError, float, " +0x3.p-1 ")
53 self.assertEqual(float(" 25.e-1 "), 2.5)
Benjamin Petersond43029b2008-09-06 23:33:21 +000054 self.assertEqual(support.fcmp(float(" .25e-1 "), .025), 0)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000055
56 def test_floatconversion(self):
57 # Make sure that calls to __float__() work properly
58 class Foo0:
59 def __float__(self):
60 return 42.
61
62 class Foo1(object):
63 def __float__(self):
64 return 42.
65
66 class Foo2(float):
67 def __float__(self):
68 return 42.
69
70 class Foo3(float):
71 def __new__(cls, value=0.):
72 return float.__new__(cls, 2*value)
73
74 def __float__(self):
75 return self
76
77 class Foo4(float):
78 def __float__(self):
79 return 42
80
Benjamin Peterson2808d3c2009-04-15 21:34:27 +000081 # Issue 5759: __float__ not called on str subclasses (though it is on
82 # unicode subclasses).
83 class FooStr(str):
84 def __float__(self):
85 return float(str(self)) + 1
86
Christian Heimes81ee3ef2008-05-04 22:42:01 +000087 self.assertAlmostEqual(float(Foo0()), 42.)
88 self.assertAlmostEqual(float(Foo1()), 42.)
89 self.assertAlmostEqual(float(Foo2()), 42.)
90 self.assertAlmostEqual(float(Foo3(21)), 42.)
91 self.assertRaises(TypeError, float, Foo4(42))
Benjamin Peterson2808d3c2009-04-15 21:34:27 +000092 self.assertAlmostEqual(float(FooStr('8')), 9.)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000093
94 def test_floatasratio(self):
95 for f, ratio in [
96 (0.875, (7, 8)),
97 (-0.875, (-7, 8)),
98 (0.0, (0, 1)),
99 (11.5, (23, 2)),
100 ]:
101 self.assertEqual(f.as_integer_ratio(), ratio)
102
103 for i in range(10000):
104 f = random.random()
105 f *= 10 ** random.randint(-100, 100)
106 n, d = f.as_integer_ratio()
107 self.assertEqual(float(n).__truediv__(d), f)
108
109 R = fractions.Fraction
110 self.assertEqual(R(0, 1),
111 R(*float(0.0).as_integer_ratio()))
112 self.assertEqual(R(5, 2),
113 R(*float(2.5).as_integer_ratio()))
114 self.assertEqual(R(1, 2),
115 R(*float(0.5).as_integer_ratio()))
116 self.assertEqual(R(4728779608739021, 2251799813685248),
117 R(*float(2.1).as_integer_ratio()))
118 self.assertEqual(R(-4728779608739021, 2251799813685248),
119 R(*float(-2.1).as_integer_ratio()))
120 self.assertEqual(R(-2100, 1),
121 R(*float(-2100.0).as_integer_ratio()))
122
123 self.assertRaises(OverflowError, float('inf').as_integer_ratio)
124 self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
125 self.assertRaises(ValueError, float('nan').as_integer_ratio)
126
Mark Dickinson4a1f5932008-11-12 23:23:36 +0000127 def test_float_containment(self):
128 floats = (INF, -INF, 0.0, 1.0, NAN)
129 for f in floats:
130 self.assert_(f in [f], "'%r' not in []" % f)
131 self.assert_(f in (f,), "'%r' not in ()" % f)
132 self.assert_(f in {f}, "'%r' not in set()" % f)
133 self.assert_(f in {f: None}, "'%r' not in {}" % f)
134 self.assertEqual([f].count(f), 1, "[].count('%r') != 1" % f)
135 self.assert_(f in floats, "'%r' not in container" % f)
136
137 for f in floats:
138 # nonidentical containers, same type, same contents
139 self.assert_([f] == [f], "[%r] != [%r]" % (f, f))
140 self.assert_((f,) == (f,), "(%r,) != (%r,)" % (f, f))
141 self.assert_({f} == {f}, "{%r} != {%r}" % (f, f))
142 self.assert_({f : None} == {f: None}, "{%r : None} != "
143 "{%r : None}" % (f, f))
144
145 # identical containers
146 l, t, s, d = [f], (f,), {f}, {f: None}
147 self.assert_(l == l, "[%r] not equal to itself" % f)
148 self.assert_(t == t, "(%r,) not equal to itself" % f)
149 self.assert_(s == s, "{%r} not equal to itself" % f)
150 self.assert_(d == d, "{%r : None} not equal to itself" % f)
151
152
153
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000154class FormatFunctionsTestCase(unittest.TestCase):
155
156 def setUp(self):
157 self.save_formats = {'double':float.__getformat__('double'),
158 'float':float.__getformat__('float')}
159
160 def tearDown(self):
161 float.__setformat__('double', self.save_formats['double'])
162 float.__setformat__('float', self.save_formats['float'])
163
164 def test_getformat(self):
165 self.assert_(float.__getformat__('double') in
166 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
167 self.assert_(float.__getformat__('float') in
168 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
169 self.assertRaises(ValueError, float.__getformat__, 'chicken')
170 self.assertRaises(TypeError, float.__getformat__, 1)
171
172 def test_setformat(self):
173 for t in 'double', 'float':
174 float.__setformat__(t, 'unknown')
175 if self.save_formats[t] == 'IEEE, big-endian':
176 self.assertRaises(ValueError, float.__setformat__,
177 t, 'IEEE, little-endian')
178 elif self.save_formats[t] == 'IEEE, little-endian':
179 self.assertRaises(ValueError, float.__setformat__,
180 t, 'IEEE, big-endian')
181 else:
182 self.assertRaises(ValueError, float.__setformat__,
183 t, 'IEEE, big-endian')
184 self.assertRaises(ValueError, float.__setformat__,
185 t, 'IEEE, little-endian')
186 self.assertRaises(ValueError, float.__setformat__,
187 t, 'chicken')
188 self.assertRaises(ValueError, float.__setformat__,
189 'chicken', 'unknown')
190
Guido van Rossum2be161d2007-05-15 20:43:51 +0000191BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000192LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000193BE_DOUBLE_NAN = b'\x7f\xf8\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000194LE_DOUBLE_NAN = bytes(reversed(BE_DOUBLE_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000195
Guido van Rossum2be161d2007-05-15 20:43:51 +0000196BE_FLOAT_INF = b'\x7f\x80\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000197LE_FLOAT_INF = bytes(reversed(BE_FLOAT_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000198BE_FLOAT_NAN = b'\x7f\xc0\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000199LE_FLOAT_NAN = bytes(reversed(BE_FLOAT_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000200
201# on non-IEEE platforms, attempting to unpack a bit pattern
202# representing an infinity or a NaN should raise an exception.
203
204class UnknownFormatTestCase(unittest.TestCase):
205 def setUp(self):
206 self.save_formats = {'double':float.__getformat__('double'),
207 'float':float.__getformat__('float')}
208 float.__setformat__('double', 'unknown')
209 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000210
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000211 def tearDown(self):
212 float.__setformat__('double', self.save_formats['double'])
213 float.__setformat__('float', self.save_formats['float'])
214
215 def test_double_specials_dont_unpack(self):
216 for fmt, data in [('>d', BE_DOUBLE_INF),
217 ('>d', BE_DOUBLE_NAN),
218 ('<d', LE_DOUBLE_INF),
219 ('<d', LE_DOUBLE_NAN)]:
220 self.assertRaises(ValueError, struct.unpack, fmt, data)
221
222 def test_float_specials_dont_unpack(self):
223 for fmt, data in [('>f', BE_FLOAT_INF),
224 ('>f', BE_FLOAT_NAN),
225 ('<f', LE_FLOAT_INF),
226 ('<f', LE_FLOAT_NAN)]:
227 self.assertRaises(ValueError, struct.unpack, fmt, data)
228
229
230# on an IEEE platform, all we guarantee is that bit patterns
231# representing infinities or NaNs do not raise an exception; all else
232# is accident (today).
Guido van Rossum04110fb2007-08-24 16:32:05 +0000233# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000234
235class IEEEFormatTestCase(unittest.TestCase):
236 if float.__getformat__("double").startswith("IEEE"):
237 def test_double_specials_do_unpack(self):
238 for fmt, data in [('>d', BE_DOUBLE_INF),
239 ('>d', BE_DOUBLE_NAN),
240 ('<d', LE_DOUBLE_INF),
241 ('<d', LE_DOUBLE_NAN)]:
242 struct.unpack(fmt, data)
243
244 if float.__getformat__("float").startswith("IEEE"):
245 def test_float_specials_do_unpack(self):
246 for fmt, data in [('>f', BE_FLOAT_INF),
247 ('>f', BE_FLOAT_NAN),
248 ('<f', LE_FLOAT_INF),
249 ('<f', LE_FLOAT_NAN)]:
250 struct.unpack(fmt, data)
251
Guido van Rossum04110fb2007-08-24 16:32:05 +0000252 if float.__getformat__("double").startswith("IEEE"):
253 def test_negative_zero(self):
254 import math
255 def pos_pos():
256 return 0.0, math.atan2(0.0, -1)
257 def pos_neg():
258 return 0.0, math.atan2(-0.0, -1)
259 def neg_pos():
260 return -0.0, math.atan2(0.0, -1)
261 def neg_neg():
262 return -0.0, math.atan2(-0.0, -1)
263 self.assertEquals(pos_pos(), neg_pos())
264 self.assertEquals(pos_neg(), neg_neg())
265
Eric Smith8c663262007-08-25 02:26:07 +0000266class FormatTestCase(unittest.TestCase):
Eric Smith11fe3e02007-08-31 01:33:06 +0000267 def test_format(self):
Eric Smith8c663262007-08-25 02:26:07 +0000268 # these should be rewritten to use both format(x, spec) and
269 # x.__format__(spec)
270
271 self.assertEqual(format(0.0, 'f'), '0.000000')
272
273 # the default is 'g', except for empty format spec
274 self.assertEqual(format(0.0, ''), '0.0')
275 self.assertEqual(format(0.01, ''), '0.01')
276 self.assertEqual(format(0.01, 'g'), '0.01')
277
Eric Smith8c663262007-08-25 02:26:07 +0000278
279 self.assertEqual(format(1.0, 'f'), '1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000280
281 self.assertEqual(format(-1.0, 'f'), '-1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000282
283 self.assertEqual(format( 1.0, ' f'), ' 1.000000')
284 self.assertEqual(format(-1.0, ' f'), '-1.000000')
285 self.assertEqual(format( 1.0, '+f'), '+1.000000')
286 self.assertEqual(format(-1.0, '+f'), '-1.000000')
287
288 # % formatting
289 self.assertEqual(format(-1.0, '%'), '-100.000000%')
290
291 # conversion to string should fail
292 self.assertRaises(ValueError, format, 3.0, "s")
293
Eric Smith7b69c6c2008-01-27 21:07:59 +0000294 # other format specifiers shouldn't work on floats,
295 # in particular int specifiers
296 for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
297 [chr(x) for x in range(ord('A'), ord('Z')+1)]):
298 if not format_spec in 'eEfFgGn%':
299 self.assertRaises(ValueError, format, 0.0, format_spec)
300 self.assertRaises(ValueError, format, 1.0, format_spec)
301 self.assertRaises(ValueError, format, -1.0, format_spec)
302 self.assertRaises(ValueError, format, 1e100, format_spec)
303 self.assertRaises(ValueError, format, -1e100, format_spec)
304 self.assertRaises(ValueError, format, 1e-100, format_spec)
305 self.assertRaises(ValueError, format, -1e-100, format_spec)
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000306
Christian Heimes827b35c2007-12-10 22:19:17 +0000307class ReprTestCase(unittest.TestCase):
308 def test_repr(self):
309 floats_file = open(os.path.join(os.path.split(__file__)[0],
310 'floating_points.txt'))
311 for line in floats_file:
312 line = line.strip()
313 if not line or line.startswith('#'):
314 continue
315 v = eval(line)
316 self.assertEqual(v, eval(repr(v)))
317 floats_file.close()
318
Christian Heimes99170a52007-12-19 02:07:34 +0000319# Beginning with Python 2.6 float has cross platform compatible
Georg Brandl2ee470f2008-07-16 12:55:28 +0000320# ways to create and represent inf and nan
Christian Heimes99170a52007-12-19 02:07:34 +0000321class InfNanTest(unittest.TestCase):
322 def test_inf_from_str(self):
323 self.assert_(isinf(float("inf")))
324 self.assert_(isinf(float("+inf")))
325 self.assert_(isinf(float("-inf")))
Georg Brandl2ee470f2008-07-16 12:55:28 +0000326 self.assert_(isinf(float("infinity")))
327 self.assert_(isinf(float("+infinity")))
328 self.assert_(isinf(float("-infinity")))
Christian Heimes99170a52007-12-19 02:07:34 +0000329
330 self.assertEqual(repr(float("inf")), "inf")
331 self.assertEqual(repr(float("+inf")), "inf")
332 self.assertEqual(repr(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000333 self.assertEqual(repr(float("infinity")), "inf")
334 self.assertEqual(repr(float("+infinity")), "inf")
335 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000336
337 self.assertEqual(repr(float("INF")), "inf")
338 self.assertEqual(repr(float("+Inf")), "inf")
339 self.assertEqual(repr(float("-iNF")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000340 self.assertEqual(repr(float("Infinity")), "inf")
341 self.assertEqual(repr(float("+iNfInItY")), "inf")
342 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000343
344 self.assertEqual(str(float("inf")), "inf")
345 self.assertEqual(str(float("+inf")), "inf")
346 self.assertEqual(str(float("-inf")), "-inf")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000347 self.assertEqual(str(float("infinity")), "inf")
348 self.assertEqual(str(float("+infinity")), "inf")
349 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes99170a52007-12-19 02:07:34 +0000350
351 self.assertRaises(ValueError, float, "info")
352 self.assertRaises(ValueError, float, "+info")
353 self.assertRaises(ValueError, float, "-info")
354 self.assertRaises(ValueError, float, "in")
355 self.assertRaises(ValueError, float, "+in")
356 self.assertRaises(ValueError, float, "-in")
Georg Brandl2ee470f2008-07-16 12:55:28 +0000357 self.assertRaises(ValueError, float, "infinit")
358 self.assertRaises(ValueError, float, "+Infin")
359 self.assertRaises(ValueError, float, "-INFI")
360 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes99170a52007-12-19 02:07:34 +0000361
362 def test_inf_as_str(self):
363 self.assertEqual(repr(1e300 * 1e300), "inf")
364 self.assertEqual(repr(-1e300 * 1e300), "-inf")
365
366 self.assertEqual(str(1e300 * 1e300), "inf")
367 self.assertEqual(str(-1e300 * 1e300), "-inf")
368
369 def test_nan_from_str(self):
370 self.assert_(isnan(float("nan")))
371 self.assert_(isnan(float("+nan")))
372 self.assert_(isnan(float("-nan")))
373
374 self.assertEqual(repr(float("nan")), "nan")
375 self.assertEqual(repr(float("+nan")), "nan")
376 self.assertEqual(repr(float("-nan")), "nan")
377
378 self.assertEqual(repr(float("NAN")), "nan")
379 self.assertEqual(repr(float("+NAn")), "nan")
380 self.assertEqual(repr(float("-NaN")), "nan")
381
382 self.assertEqual(str(float("nan")), "nan")
383 self.assertEqual(str(float("+nan")), "nan")
384 self.assertEqual(str(float("-nan")), "nan")
385
386 self.assertRaises(ValueError, float, "nana")
387 self.assertRaises(ValueError, float, "+nana")
388 self.assertRaises(ValueError, float, "-nana")
389 self.assertRaises(ValueError, float, "na")
390 self.assertRaises(ValueError, float, "+na")
391 self.assertRaises(ValueError, float, "-na")
392
393 def test_nan_as_str(self):
394 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
395 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
396
397 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
398 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes827b35c2007-12-10 22:19:17 +0000399
Christian Heimes53876d92008-04-19 00:31:39 +0000400 def notest_float_nan(self):
401 self.assert_(NAN.is_nan())
402 self.failIf(INF.is_nan())
403 self.failIf((0.).is_nan())
404
405 def notest_float_inf(self):
406 self.assert_(INF.is_inf())
407 self.failIf(NAN.is_inf())
408 self.failIf((0.).is_inf())
409
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000410fromHex = float.fromhex
411toHex = float.hex
412class HexFloatTestCase(unittest.TestCase):
413 MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
414 MIN = fromHex('0x1p-1022') # min normal
415 TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
416 EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
417
418 def identical(self, x, y):
419 # check that floats x and y are identical, or that both
420 # are NaNs
421 if isnan(x) or isnan(y):
422 if isnan(x) == isnan(y):
423 return
424 elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
425 return
426 self.fail('%r not identical to %r' % (x, y))
427
428 def test_ends(self):
Mark Dickinson38bbc482008-07-16 11:32:23 +0000429 self.identical(self.MIN, ldexp(1.0, -1022))
430 self.identical(self.TINY, ldexp(1.0, -1074))
431 self.identical(self.EPS, ldexp(1.0, -52))
432 self.identical(self.MAX, 2.*(ldexp(1.0, 1023) - ldexp(1.0, 970)))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000433
434 def test_invalid_inputs(self):
435 invalid_inputs = [
436 'infi', # misspelt infinities and nans
437 '-Infinit',
438 '++inf',
439 '-+Inf',
440 '--nan',
441 '+-NaN',
442 'snan',
443 'NaNs',
444 'nna',
445 '0xnan',
446 '',
447 ' ',
448 'x1.0p0',
449 '0xX1.0p0',
450 '+ 0x1.0p0', # internal whitespace
451 '- 0x1.0p0',
452 '0 x1.0p0',
453 '0x 1.0p0',
454 '0x1 2.0p0',
455 '+0x1 .0p0',
456 '0x1. 0p0',
457 '-0x1.0 1p0',
458 '-0x1.0 p0',
459 '+0x1.0p +0',
460 '0x1.0p -0',
461 '0x1.0p 0',
462 '+0x1.0p+ 0',
463 '-0x1.0p- 0',
464 '++0x1.0p-0', # double signs
465 '--0x1.0p0',
466 '+-0x1.0p+0',
467 '-+0x1.0p0',
468 '0x1.0p++0',
469 '+0x1.0p+-0',
470 '-0x1.0p-+0',
471 '0x1.0p--0',
472 '0x1.0.p0',
473 '0x.p0', # no hex digits before or after point
474 '0x1,p0', # wrong decimal point character
475 '0x1pa',
476 '0x1p\uff10', # fullwidth Unicode digits
477 '\uff10x1p0',
478 '0x\uff11p0',
479 '0x1.\uff10p0',
480 '0x1p0 \n 0x2p0',
481 '0x1p0\0 0x1p0', # embedded null byte is not end of string
482 ]
483 for x in invalid_inputs:
Mark Dickinson589b7952008-08-21 20:05:56 +0000484 try:
485 result = fromHex(x)
486 except ValueError:
487 pass
488 else:
489 self.fail('Expected float.fromhex(%r) to raise ValueError; '
490 'got %r instead' % (x, result))
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000491
492
493 def test_from_hex(self):
494 MIN = self.MIN;
495 MAX = self.MAX;
496 TINY = self.TINY;
497 EPS = self.EPS;
498
499 # two spellings of infinity, with optional signs; case-insensitive
500 self.identical(fromHex('inf'), INF)
501 self.identical(fromHex('+Inf'), INF)
502 self.identical(fromHex('-INF'), -INF)
503 self.identical(fromHex('iNf'), INF)
504 self.identical(fromHex('Infinity'), INF)
505 self.identical(fromHex('+INFINITY'), INF)
506 self.identical(fromHex('-infinity'), -INF)
507 self.identical(fromHex('-iNFiNitY'), -INF)
508
509 # nans with optional sign; case insensitive
510 self.identical(fromHex('nan'), NAN)
511 self.identical(fromHex('+NaN'), NAN)
512 self.identical(fromHex('-NaN'), NAN)
513 self.identical(fromHex('-nAN'), NAN)
514
515 # variations in input format
516 self.identical(fromHex('1'), 1.0)
517 self.identical(fromHex('+1'), 1.0)
518 self.identical(fromHex('1.'), 1.0)
519 self.identical(fromHex('1.0'), 1.0)
520 self.identical(fromHex('1.0p0'), 1.0)
521 self.identical(fromHex('01'), 1.0)
522 self.identical(fromHex('01.'), 1.0)
523 self.identical(fromHex('0x1'), 1.0)
524 self.identical(fromHex('0x1.'), 1.0)
525 self.identical(fromHex('0x1.0'), 1.0)
526 self.identical(fromHex('+0x1.0'), 1.0)
527 self.identical(fromHex('0x1p0'), 1.0)
528 self.identical(fromHex('0X1p0'), 1.0)
529 self.identical(fromHex('0X1P0'), 1.0)
530 self.identical(fromHex('0x1P0'), 1.0)
531 self.identical(fromHex('0x1.p0'), 1.0)
532 self.identical(fromHex('0x1.0p0'), 1.0)
533 self.identical(fromHex('0x.1p4'), 1.0)
534 self.identical(fromHex('0x.1p04'), 1.0)
535 self.identical(fromHex('0x.1p004'), 1.0)
536 self.identical(fromHex('0x1p+0'), 1.0)
537 self.identical(fromHex('0x1P-0'), 1.0)
538 self.identical(fromHex('+0x1p0'), 1.0)
539 self.identical(fromHex('0x01p0'), 1.0)
540 self.identical(fromHex('0x1p00'), 1.0)
541 self.identical(fromHex(' 0x1p0 '), 1.0)
542 self.identical(fromHex('\n 0x1p0'), 1.0)
543 self.identical(fromHex('0x1p0 \t'), 1.0)
544 self.identical(fromHex('0xap0'), 10.0)
545 self.identical(fromHex('0xAp0'), 10.0)
546 self.identical(fromHex('0xaP0'), 10.0)
547 self.identical(fromHex('0xAP0'), 10.0)
548 self.identical(fromHex('0xbep0'), 190.0)
549 self.identical(fromHex('0xBep0'), 190.0)
550 self.identical(fromHex('0xbEp0'), 190.0)
551 self.identical(fromHex('0XBE0P-4'), 190.0)
552 self.identical(fromHex('0xBEp0'), 190.0)
553 self.identical(fromHex('0xB.Ep4'), 190.0)
554 self.identical(fromHex('0x.BEp8'), 190.0)
555 self.identical(fromHex('0x.0BEp12'), 190.0)
556
557 # moving the point around
558 pi = fromHex('0x1.921fb54442d18p1')
559 self.identical(fromHex('0x.006487ed5110b46p11'), pi)
560 self.identical(fromHex('0x.00c90fdaa22168cp10'), pi)
561 self.identical(fromHex('0x.01921fb54442d18p9'), pi)
562 self.identical(fromHex('0x.03243f6a8885a3p8'), pi)
563 self.identical(fromHex('0x.06487ed5110b46p7'), pi)
564 self.identical(fromHex('0x.0c90fdaa22168cp6'), pi)
565 self.identical(fromHex('0x.1921fb54442d18p5'), pi)
566 self.identical(fromHex('0x.3243f6a8885a3p4'), pi)
567 self.identical(fromHex('0x.6487ed5110b46p3'), pi)
568 self.identical(fromHex('0x.c90fdaa22168cp2'), pi)
569 self.identical(fromHex('0x1.921fb54442d18p1'), pi)
570 self.identical(fromHex('0x3.243f6a8885a3p0'), pi)
571 self.identical(fromHex('0x6.487ed5110b46p-1'), pi)
572 self.identical(fromHex('0xc.90fdaa22168cp-2'), pi)
573 self.identical(fromHex('0x19.21fb54442d18p-3'), pi)
574 self.identical(fromHex('0x32.43f6a8885a3p-4'), pi)
575 self.identical(fromHex('0x64.87ed5110b46p-5'), pi)
576 self.identical(fromHex('0xc9.0fdaa22168cp-6'), pi)
577 self.identical(fromHex('0x192.1fb54442d18p-7'), pi)
578 self.identical(fromHex('0x324.3f6a8885a3p-8'), pi)
579 self.identical(fromHex('0x648.7ed5110b46p-9'), pi)
580 self.identical(fromHex('0xc90.fdaa22168cp-10'), pi)
581 self.identical(fromHex('0x1921.fb54442d18p-11'), pi)
582 # ...
583 self.identical(fromHex('0x1921fb54442d1.8p-47'), pi)
584 self.identical(fromHex('0x3243f6a8885a3p-48'), pi)
585 self.identical(fromHex('0x6487ed5110b46p-49'), pi)
586 self.identical(fromHex('0xc90fdaa22168cp-50'), pi)
587 self.identical(fromHex('0x1921fb54442d18p-51'), pi)
588 self.identical(fromHex('0x3243f6a8885a30p-52'), pi)
589 self.identical(fromHex('0x6487ed5110b460p-53'), pi)
590 self.identical(fromHex('0xc90fdaa22168c0p-54'), pi)
591 self.identical(fromHex('0x1921fb54442d180p-55'), pi)
592
593
594 # results that should overflow...
595 self.assertRaises(OverflowError, fromHex, '-0x1p1024')
596 self.assertRaises(OverflowError, fromHex, '0x1p+1025')
597 self.assertRaises(OverflowError, fromHex, '+0X1p1030')
598 self.assertRaises(OverflowError, fromHex, '-0x1p+1100')
599 self.assertRaises(OverflowError, fromHex, '0X1p123456789123456789')
600 self.assertRaises(OverflowError, fromHex, '+0X.8p+1025')
601 self.assertRaises(OverflowError, fromHex, '+0x0.8p1025')
602 self.assertRaises(OverflowError, fromHex, '-0x0.4p1026')
603 self.assertRaises(OverflowError, fromHex, '0X2p+1023')
604 self.assertRaises(OverflowError, fromHex, '0x2.p1023')
605 self.assertRaises(OverflowError, fromHex, '-0x2.0p+1023')
606 self.assertRaises(OverflowError, fromHex, '+0X4p+1022')
607 self.assertRaises(OverflowError, fromHex, '0x1.ffffffffffffffp+1023')
608 self.assertRaises(OverflowError, fromHex, '-0X1.fffffffffffff9p1023')
609 self.assertRaises(OverflowError, fromHex, '0X1.fffffffffffff8p1023')
610 self.assertRaises(OverflowError, fromHex, '+0x3.fffffffffffffp1022')
611 self.assertRaises(OverflowError, fromHex, '0x3fffffffffffffp+970')
612 self.assertRaises(OverflowError, fromHex, '0x10000000000000000p960')
613 self.assertRaises(OverflowError, fromHex, '-0Xffffffffffffffffp960')
614
615 # ...and those that round to +-max float
616 self.identical(fromHex('+0x1.fffffffffffffp+1023'), MAX)
617 self.identical(fromHex('-0X1.fffffffffffff7p1023'), -MAX)
618 self.identical(fromHex('0X1.fffffffffffff7fffffffffffffp1023'), MAX)
619
620 # zeros
621 self.identical(fromHex('0x0p0'), 0.0)
622 self.identical(fromHex('0x0p1000'), 0.0)
623 self.identical(fromHex('-0x0p1023'), -0.0)
624 self.identical(fromHex('0X0p1024'), 0.0)
625 self.identical(fromHex('-0x0p1025'), -0.0)
626 self.identical(fromHex('0X0p2000'), 0.0)
627 self.identical(fromHex('0x0p123456789123456789'), 0.0)
628 self.identical(fromHex('-0X0p-0'), -0.0)
629 self.identical(fromHex('-0X0p-1000'), -0.0)
630 self.identical(fromHex('0x0p-1023'), 0.0)
631 self.identical(fromHex('-0X0p-1024'), -0.0)
632 self.identical(fromHex('-0x0p-1025'), -0.0)
633 self.identical(fromHex('-0x0p-1072'), -0.0)
634 self.identical(fromHex('0X0p-1073'), 0.0)
635 self.identical(fromHex('-0x0p-1074'), -0.0)
636 self.identical(fromHex('0x0p-1075'), 0.0)
637 self.identical(fromHex('0X0p-1076'), 0.0)
638 self.identical(fromHex('-0X0p-2000'), -0.0)
639 self.identical(fromHex('-0x0p-123456789123456789'), -0.0)
640
641 # values that should underflow to 0
642 self.identical(fromHex('0X1p-1075'), 0.0)
643 self.identical(fromHex('-0X1p-1075'), -0.0)
644 self.identical(fromHex('-0x1p-123456789123456789'), -0.0)
645 self.identical(fromHex('0x1.00000000000000001p-1075'), TINY)
646 self.identical(fromHex('-0x1.1p-1075'), -TINY)
647 self.identical(fromHex('0x1.fffffffffffffffffp-1075'), TINY)
648
649 # check round-half-even is working correctly near 0 ...
650 self.identical(fromHex('0x1p-1076'), 0.0)
651 self.identical(fromHex('0X2p-1076'), 0.0)
652 self.identical(fromHex('0X3p-1076'), TINY)
653 self.identical(fromHex('0x4p-1076'), TINY)
654 self.identical(fromHex('0X5p-1076'), TINY)
655 self.identical(fromHex('0X6p-1076'), 2*TINY)
656 self.identical(fromHex('0x7p-1076'), 2*TINY)
657 self.identical(fromHex('0X8p-1076'), 2*TINY)
658 self.identical(fromHex('0X9p-1076'), 2*TINY)
659 self.identical(fromHex('0xap-1076'), 2*TINY)
660 self.identical(fromHex('0Xbp-1076'), 3*TINY)
661 self.identical(fromHex('0xcp-1076'), 3*TINY)
662 self.identical(fromHex('0Xdp-1076'), 3*TINY)
663 self.identical(fromHex('0Xep-1076'), 4*TINY)
664 self.identical(fromHex('0xfp-1076'), 4*TINY)
665 self.identical(fromHex('0x10p-1076'), 4*TINY)
666 self.identical(fromHex('-0x1p-1076'), -0.0)
667 self.identical(fromHex('-0X2p-1076'), -0.0)
668 self.identical(fromHex('-0x3p-1076'), -TINY)
669 self.identical(fromHex('-0X4p-1076'), -TINY)
670 self.identical(fromHex('-0x5p-1076'), -TINY)
671 self.identical(fromHex('-0x6p-1076'), -2*TINY)
672 self.identical(fromHex('-0X7p-1076'), -2*TINY)
673 self.identical(fromHex('-0X8p-1076'), -2*TINY)
674 self.identical(fromHex('-0X9p-1076'), -2*TINY)
675 self.identical(fromHex('-0Xap-1076'), -2*TINY)
676 self.identical(fromHex('-0xbp-1076'), -3*TINY)
677 self.identical(fromHex('-0xcp-1076'), -3*TINY)
678 self.identical(fromHex('-0Xdp-1076'), -3*TINY)
679 self.identical(fromHex('-0xep-1076'), -4*TINY)
680 self.identical(fromHex('-0Xfp-1076'), -4*TINY)
681 self.identical(fromHex('-0X10p-1076'), -4*TINY)
682
683 # ... and near MIN ...
684 self.identical(fromHex('0x0.ffffffffffffd6p-1022'), MIN-3*TINY)
685 self.identical(fromHex('0x0.ffffffffffffd8p-1022'), MIN-2*TINY)
686 self.identical(fromHex('0x0.ffffffffffffdap-1022'), MIN-2*TINY)
687 self.identical(fromHex('0x0.ffffffffffffdcp-1022'), MIN-2*TINY)
688 self.identical(fromHex('0x0.ffffffffffffdep-1022'), MIN-2*TINY)
689 self.identical(fromHex('0x0.ffffffffffffe0p-1022'), MIN-2*TINY)
690 self.identical(fromHex('0x0.ffffffffffffe2p-1022'), MIN-2*TINY)
691 self.identical(fromHex('0x0.ffffffffffffe4p-1022'), MIN-2*TINY)
692 self.identical(fromHex('0x0.ffffffffffffe6p-1022'), MIN-2*TINY)
693 self.identical(fromHex('0x0.ffffffffffffe8p-1022'), MIN-2*TINY)
694 self.identical(fromHex('0x0.ffffffffffffeap-1022'), MIN-TINY)
695 self.identical(fromHex('0x0.ffffffffffffecp-1022'), MIN-TINY)
696 self.identical(fromHex('0x0.ffffffffffffeep-1022'), MIN-TINY)
697 self.identical(fromHex('0x0.fffffffffffff0p-1022'), MIN-TINY)
698 self.identical(fromHex('0x0.fffffffffffff2p-1022'), MIN-TINY)
699 self.identical(fromHex('0x0.fffffffffffff4p-1022'), MIN-TINY)
700 self.identical(fromHex('0x0.fffffffffffff6p-1022'), MIN-TINY)
701 self.identical(fromHex('0x0.fffffffffffff8p-1022'), MIN)
702 self.identical(fromHex('0x0.fffffffffffffap-1022'), MIN)
703 self.identical(fromHex('0x0.fffffffffffffcp-1022'), MIN)
704 self.identical(fromHex('0x0.fffffffffffffep-1022'), MIN)
705 self.identical(fromHex('0x1.00000000000000p-1022'), MIN)
706 self.identical(fromHex('0x1.00000000000002p-1022'), MIN)
707 self.identical(fromHex('0x1.00000000000004p-1022'), MIN)
708 self.identical(fromHex('0x1.00000000000006p-1022'), MIN)
709 self.identical(fromHex('0x1.00000000000008p-1022'), MIN)
710 self.identical(fromHex('0x1.0000000000000ap-1022'), MIN+TINY)
711 self.identical(fromHex('0x1.0000000000000cp-1022'), MIN+TINY)
712 self.identical(fromHex('0x1.0000000000000ep-1022'), MIN+TINY)
713 self.identical(fromHex('0x1.00000000000010p-1022'), MIN+TINY)
714 self.identical(fromHex('0x1.00000000000012p-1022'), MIN+TINY)
715 self.identical(fromHex('0x1.00000000000014p-1022'), MIN+TINY)
716 self.identical(fromHex('0x1.00000000000016p-1022'), MIN+TINY)
717 self.identical(fromHex('0x1.00000000000018p-1022'), MIN+2*TINY)
718
719 # ... and near 1.0.
720 self.identical(fromHex('0x0.fffffffffffff0p0'), 1.0-EPS)
721 self.identical(fromHex('0x0.fffffffffffff1p0'), 1.0-EPS)
722 self.identical(fromHex('0X0.fffffffffffff2p0'), 1.0-EPS)
723 self.identical(fromHex('0x0.fffffffffffff3p0'), 1.0-EPS)
724 self.identical(fromHex('0X0.fffffffffffff4p0'), 1.0-EPS)
725 self.identical(fromHex('0X0.fffffffffffff5p0'), 1.0-EPS/2)
726 self.identical(fromHex('0X0.fffffffffffff6p0'), 1.0-EPS/2)
727 self.identical(fromHex('0x0.fffffffffffff7p0'), 1.0-EPS/2)
728 self.identical(fromHex('0x0.fffffffffffff8p0'), 1.0-EPS/2)
729 self.identical(fromHex('0X0.fffffffffffff9p0'), 1.0-EPS/2)
730 self.identical(fromHex('0X0.fffffffffffffap0'), 1.0-EPS/2)
731 self.identical(fromHex('0x0.fffffffffffffbp0'), 1.0-EPS/2)
732 self.identical(fromHex('0X0.fffffffffffffcp0'), 1.0)
733 self.identical(fromHex('0x0.fffffffffffffdp0'), 1.0)
734 self.identical(fromHex('0X0.fffffffffffffep0'), 1.0)
735 self.identical(fromHex('0x0.ffffffffffffffp0'), 1.0)
736 self.identical(fromHex('0X1.00000000000000p0'), 1.0)
737 self.identical(fromHex('0X1.00000000000001p0'), 1.0)
738 self.identical(fromHex('0x1.00000000000002p0'), 1.0)
739 self.identical(fromHex('0X1.00000000000003p0'), 1.0)
740 self.identical(fromHex('0x1.00000000000004p0'), 1.0)
741 self.identical(fromHex('0X1.00000000000005p0'), 1.0)
742 self.identical(fromHex('0X1.00000000000006p0'), 1.0)
743 self.identical(fromHex('0X1.00000000000007p0'), 1.0)
744 self.identical(fromHex('0x1.00000000000007ffffffffffffffffffffp0'),
745 1.0)
746 self.identical(fromHex('0x1.00000000000008p0'), 1.0)
747 self.identical(fromHex('0x1.00000000000008000000000000000001p0'),
748 1+EPS)
749 self.identical(fromHex('0X1.00000000000009p0'), 1.0+EPS)
750 self.identical(fromHex('0x1.0000000000000ap0'), 1.0+EPS)
751 self.identical(fromHex('0x1.0000000000000bp0'), 1.0+EPS)
752 self.identical(fromHex('0X1.0000000000000cp0'), 1.0+EPS)
753 self.identical(fromHex('0x1.0000000000000dp0'), 1.0+EPS)
754 self.identical(fromHex('0x1.0000000000000ep0'), 1.0+EPS)
755 self.identical(fromHex('0X1.0000000000000fp0'), 1.0+EPS)
756 self.identical(fromHex('0x1.00000000000010p0'), 1.0+EPS)
757 self.identical(fromHex('0X1.00000000000011p0'), 1.0+EPS)
758 self.identical(fromHex('0x1.00000000000012p0'), 1.0+EPS)
759 self.identical(fromHex('0X1.00000000000013p0'), 1.0+EPS)
760 self.identical(fromHex('0X1.00000000000014p0'), 1.0+EPS)
761 self.identical(fromHex('0x1.00000000000015p0'), 1.0+EPS)
762 self.identical(fromHex('0x1.00000000000016p0'), 1.0+EPS)
763 self.identical(fromHex('0X1.00000000000017p0'), 1.0+EPS)
764 self.identical(fromHex('0x1.00000000000017ffffffffffffffffffffp0'),
765 1.0+EPS)
766 self.identical(fromHex('0x1.00000000000018p0'), 1.0+2*EPS)
767 self.identical(fromHex('0X1.00000000000018000000000000000001p0'),
768 1.0+2*EPS)
769 self.identical(fromHex('0x1.00000000000019p0'), 1.0+2*EPS)
770 self.identical(fromHex('0X1.0000000000001ap0'), 1.0+2*EPS)
771 self.identical(fromHex('0X1.0000000000001bp0'), 1.0+2*EPS)
772 self.identical(fromHex('0x1.0000000000001cp0'), 1.0+2*EPS)
773 self.identical(fromHex('0x1.0000000000001dp0'), 1.0+2*EPS)
774 self.identical(fromHex('0x1.0000000000001ep0'), 1.0+2*EPS)
775 self.identical(fromHex('0X1.0000000000001fp0'), 1.0+2*EPS)
776 self.identical(fromHex('0x1.00000000000020p0'), 1.0+2*EPS)
777
778 def test_roundtrip(self):
779 def roundtrip(x):
780 return fromHex(toHex(x))
781
782 for x in [NAN, INF, self.MAX, self.MIN, self.MIN-self.TINY, self.TINY, 0.0]:
783 self.identical(x, roundtrip(x))
784 self.identical(-x, roundtrip(-x))
785
786 # fromHex(toHex(x)) should exactly recover x, for any non-NaN float x.
787 import random
788 for i in range(10000):
789 e = random.randrange(-1200, 1200)
790 m = random.random()
791 s = random.choice([1.0, -1.0])
792 try:
793 x = s*ldexp(m, e)
794 except OverflowError:
795 pass
796 else:
797 self.identical(x, fromHex(toHex(x)))
798
Christian Heimes53876d92008-04-19 00:31:39 +0000799
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000800def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000801 support.run_unittest(
Amaury Forgeot d'Arc7e958d12008-09-06 21:03:22 +0000802 GeneralFloatCases,
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000803 FormatFunctionsTestCase,
804 UnknownFormatTestCase,
Eric Smith8c663262007-08-25 02:26:07 +0000805 IEEEFormatTestCase,
Christian Heimes827b35c2007-12-10 22:19:17 +0000806 FormatTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +0000807 ReprTestCase,
808 InfNanTest,
Mark Dickinson65fe25e2008-07-16 11:30:51 +0000809 HexFloatTestCase,
Christian Heimesb76922a2007-12-11 01:06:40 +0000810 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000811
812if __name__ == '__main__':
813 test_main()