~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/test/test_float.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

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