blob: d17400c657c455d472ddb060c552c65f4f3f1b92 [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
6from math import isinf, isnan
7import operator
Michael W. Hudsonba283e22005-05-27 15:23:20 +00008
Christian Heimes53876d92008-04-19 00:31:39 +00009INF = float("inf")
10NAN = float("nan")
Christian Heimes99170a52007-12-19 02:07:34 +000011
Christian Heimes81ee3ef2008-05-04 22:42:01 +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(" 3.14 "), 3.14)
18 self.assertRaises(ValueError, float, " 0x3.1 ")
19 self.assertRaises(ValueError, float, " -0x3.p-1 ")
20 self.assertRaises(ValueError, float, " +0x3.p-1 ")
21 self.assertRaises(ValueError, float, "++3.14")
22 self.assertRaises(ValueError, float, "+-3.14")
23 self.assertRaises(ValueError, float, "-+3.14")
24 self.assertRaises(ValueError, float, "--3.14")
25 if have_unicode:
26 self.assertEqual(float(unicode(" 3.14 ")), 3.14)
27 self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
28 # Implementation limitation in PyFloat_FromString()
29 self.assertRaises(ValueError, float, unicode("1"*10000))
30
Benjamin Petersonee8712c2008-05-20 21:35:26 +000031 @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
Christian Heimes81ee3ef2008-05-04 22:42:01 +000032 def test_float_with_comma(self):
33 # set locale to something that doesn't use '.' for the decimal point
34 # float must not accept the locale specific decimal point but
35 # it still has to accept the normal python syntac
36 import locale
37 if not locale.localeconv()['decimal_point'] == ',':
38 return
39
40 self.assertEqual(float(" 3.14 "), 3.14)
41 self.assertEqual(float("+3.14 "), 3.14)
42 self.assertEqual(float("-3.14 "), -3.14)
43 self.assertEqual(float(".14 "), .14)
44 self.assertEqual(float("3. "), 3.0)
45 self.assertEqual(float("3.e3 "), 3000.0)
46 self.assertEqual(float("3.2e3 "), 3200.0)
47 self.assertEqual(float("2.5e-1 "), 0.25)
48 self.assertEqual(float("5e-1"), 0.5)
49 self.assertRaises(ValueError, float, " 3,14 ")
50 self.assertRaises(ValueError, float, " +3,14 ")
51 self.assertRaises(ValueError, float, " -3,14 ")
52 self.assertRaises(ValueError, float, " 0x3.1 ")
53 self.assertRaises(ValueError, float, " -0x3.p-1 ")
54 self.assertRaises(ValueError, float, " +0x3.p-1 ")
55 self.assertEqual(float(" 25.e-1 "), 2.5)
56 self.assertEqual(fcmp(float(" .25e-1 "), .025), 0)
57
58 def test_floatconversion(self):
59 # Make sure that calls to __float__() work properly
60 class Foo0:
61 def __float__(self):
62 return 42.
63
64 class Foo1(object):
65 def __float__(self):
66 return 42.
67
68 class Foo2(float):
69 def __float__(self):
70 return 42.
71
72 class Foo3(float):
73 def __new__(cls, value=0.):
74 return float.__new__(cls, 2*value)
75
76 def __float__(self):
77 return self
78
79 class Foo4(float):
80 def __float__(self):
81 return 42
82
83 self.assertAlmostEqual(float(Foo0()), 42.)
84 self.assertAlmostEqual(float(Foo1()), 42.)
85 self.assertAlmostEqual(float(Foo2()), 42.)
86 self.assertAlmostEqual(float(Foo3(21)), 42.)
87 self.assertRaises(TypeError, float, Foo4(42))
88
89 def test_floatasratio(self):
90 for f, ratio in [
91 (0.875, (7, 8)),
92 (-0.875, (-7, 8)),
93 (0.0, (0, 1)),
94 (11.5, (23, 2)),
95 ]:
96 self.assertEqual(f.as_integer_ratio(), ratio)
97
98 for i in range(10000):
99 f = random.random()
100 f *= 10 ** random.randint(-100, 100)
101 n, d = f.as_integer_ratio()
102 self.assertEqual(float(n).__truediv__(d), f)
103
104 R = fractions.Fraction
105 self.assertEqual(R(0, 1),
106 R(*float(0.0).as_integer_ratio()))
107 self.assertEqual(R(5, 2),
108 R(*float(2.5).as_integer_ratio()))
109 self.assertEqual(R(1, 2),
110 R(*float(0.5).as_integer_ratio()))
111 self.assertEqual(R(4728779608739021, 2251799813685248),
112 R(*float(2.1).as_integer_ratio()))
113 self.assertEqual(R(-4728779608739021, 2251799813685248),
114 R(*float(-2.1).as_integer_ratio()))
115 self.assertEqual(R(-2100, 1),
116 R(*float(-2100.0).as_integer_ratio()))
117
118 self.assertRaises(OverflowError, float('inf').as_integer_ratio)
119 self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
120 self.assertRaises(ValueError, float('nan').as_integer_ratio)
121
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000122class FormatFunctionsTestCase(unittest.TestCase):
123
124 def setUp(self):
125 self.save_formats = {'double':float.__getformat__('double'),
126 'float':float.__getformat__('float')}
127
128 def tearDown(self):
129 float.__setformat__('double', self.save_formats['double'])
130 float.__setformat__('float', self.save_formats['float'])
131
132 def test_getformat(self):
133 self.assert_(float.__getformat__('double') in
134 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
135 self.assert_(float.__getformat__('float') in
136 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
137 self.assertRaises(ValueError, float.__getformat__, 'chicken')
138 self.assertRaises(TypeError, float.__getformat__, 1)
139
140 def test_setformat(self):
141 for t in 'double', 'float':
142 float.__setformat__(t, 'unknown')
143 if self.save_formats[t] == 'IEEE, big-endian':
144 self.assertRaises(ValueError, float.__setformat__,
145 t, 'IEEE, little-endian')
146 elif self.save_formats[t] == 'IEEE, little-endian':
147 self.assertRaises(ValueError, float.__setformat__,
148 t, 'IEEE, big-endian')
149 else:
150 self.assertRaises(ValueError, float.__setformat__,
151 t, 'IEEE, big-endian')
152 self.assertRaises(ValueError, float.__setformat__,
153 t, 'IEEE, little-endian')
154 self.assertRaises(ValueError, float.__setformat__,
155 t, 'chicken')
156 self.assertRaises(ValueError, float.__setformat__,
157 'chicken', 'unknown')
158
Guido van Rossum2be161d2007-05-15 20:43:51 +0000159BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000160LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000161BE_DOUBLE_NAN = b'\x7f\xf8\x00\x00\x00\x00\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000162LE_DOUBLE_NAN = bytes(reversed(BE_DOUBLE_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000163
Guido van Rossum2be161d2007-05-15 20:43:51 +0000164BE_FLOAT_INF = b'\x7f\x80\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000165LE_FLOAT_INF = bytes(reversed(BE_FLOAT_INF))
Guido van Rossum2be161d2007-05-15 20:43:51 +0000166BE_FLOAT_NAN = b'\x7f\xc0\x00\x00'
Guido van Rossum254348e2007-11-21 19:29:53 +0000167LE_FLOAT_NAN = bytes(reversed(BE_FLOAT_NAN))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000168
169# on non-IEEE platforms, attempting to unpack a bit pattern
170# representing an infinity or a NaN should raise an exception.
171
172class UnknownFormatTestCase(unittest.TestCase):
173 def setUp(self):
174 self.save_formats = {'double':float.__getformat__('double'),
175 'float':float.__getformat__('float')}
176 float.__setformat__('double', 'unknown')
177 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000178
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000179 def tearDown(self):
180 float.__setformat__('double', self.save_formats['double'])
181 float.__setformat__('float', self.save_formats['float'])
182
183 def test_double_specials_dont_unpack(self):
184 for fmt, data in [('>d', BE_DOUBLE_INF),
185 ('>d', BE_DOUBLE_NAN),
186 ('<d', LE_DOUBLE_INF),
187 ('<d', LE_DOUBLE_NAN)]:
188 self.assertRaises(ValueError, struct.unpack, fmt, data)
189
190 def test_float_specials_dont_unpack(self):
191 for fmt, data in [('>f', BE_FLOAT_INF),
192 ('>f', BE_FLOAT_NAN),
193 ('<f', LE_FLOAT_INF),
194 ('<f', LE_FLOAT_NAN)]:
195 self.assertRaises(ValueError, struct.unpack, fmt, data)
196
197
198# on an IEEE platform, all we guarantee is that bit patterns
199# representing infinities or NaNs do not raise an exception; all else
200# is accident (today).
Guido van Rossum04110fb2007-08-24 16:32:05 +0000201# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000202
203class IEEEFormatTestCase(unittest.TestCase):
204 if float.__getformat__("double").startswith("IEEE"):
205 def test_double_specials_do_unpack(self):
206 for fmt, data in [('>d', BE_DOUBLE_INF),
207 ('>d', BE_DOUBLE_NAN),
208 ('<d', LE_DOUBLE_INF),
209 ('<d', LE_DOUBLE_NAN)]:
210 struct.unpack(fmt, data)
211
212 if float.__getformat__("float").startswith("IEEE"):
213 def test_float_specials_do_unpack(self):
214 for fmt, data in [('>f', BE_FLOAT_INF),
215 ('>f', BE_FLOAT_NAN),
216 ('<f', LE_FLOAT_INF),
217 ('<f', LE_FLOAT_NAN)]:
218 struct.unpack(fmt, data)
219
Guido van Rossum04110fb2007-08-24 16:32:05 +0000220 if float.__getformat__("double").startswith("IEEE"):
221 def test_negative_zero(self):
222 import math
223 def pos_pos():
224 return 0.0, math.atan2(0.0, -1)
225 def pos_neg():
226 return 0.0, math.atan2(-0.0, -1)
227 def neg_pos():
228 return -0.0, math.atan2(0.0, -1)
229 def neg_neg():
230 return -0.0, math.atan2(-0.0, -1)
231 self.assertEquals(pos_pos(), neg_pos())
232 self.assertEquals(pos_neg(), neg_neg())
233
Eric Smith8c663262007-08-25 02:26:07 +0000234class FormatTestCase(unittest.TestCase):
Eric Smith11fe3e02007-08-31 01:33:06 +0000235 def test_format(self):
Eric Smith8c663262007-08-25 02:26:07 +0000236 # these should be rewritten to use both format(x, spec) and
237 # x.__format__(spec)
238
239 self.assertEqual(format(0.0, 'f'), '0.000000')
240
241 # the default is 'g', except for empty format spec
242 self.assertEqual(format(0.0, ''), '0.0')
243 self.assertEqual(format(0.01, ''), '0.01')
244 self.assertEqual(format(0.01, 'g'), '0.01')
245
Eric Smith8c663262007-08-25 02:26:07 +0000246
247 self.assertEqual(format(1.0, 'f'), '1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000248
249 self.assertEqual(format(-1.0, 'f'), '-1.000000')
Eric Smith8c663262007-08-25 02:26:07 +0000250
251 self.assertEqual(format( 1.0, ' f'), ' 1.000000')
252 self.assertEqual(format(-1.0, ' f'), '-1.000000')
253 self.assertEqual(format( 1.0, '+f'), '+1.000000')
254 self.assertEqual(format(-1.0, '+f'), '-1.000000')
255
256 # % formatting
257 self.assertEqual(format(-1.0, '%'), '-100.000000%')
258
259 # conversion to string should fail
260 self.assertRaises(ValueError, format, 3.0, "s")
261
Eric Smith7b69c6c2008-01-27 21:07:59 +0000262 # other format specifiers shouldn't work on floats,
263 # in particular int specifiers
264 for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
265 [chr(x) for x in range(ord('A'), ord('Z')+1)]):
266 if not format_spec in 'eEfFgGn%':
267 self.assertRaises(ValueError, format, 0.0, format_spec)
268 self.assertRaises(ValueError, format, 1.0, format_spec)
269 self.assertRaises(ValueError, format, -1.0, format_spec)
270 self.assertRaises(ValueError, format, 1e100, format_spec)
271 self.assertRaises(ValueError, format, -1e100, format_spec)
272 self.assertRaises(ValueError, format, 1e-100, format_spec)
273 self.assertRaises(ValueError, format, -1e-100, format_spec)
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000274
Christian Heimes827b35c2007-12-10 22:19:17 +0000275class ReprTestCase(unittest.TestCase):
276 def test_repr(self):
277 floats_file = open(os.path.join(os.path.split(__file__)[0],
278 'floating_points.txt'))
279 for line in floats_file:
280 line = line.strip()
281 if not line or line.startswith('#'):
282 continue
283 v = eval(line)
284 self.assertEqual(v, eval(repr(v)))
285 floats_file.close()
286
Christian Heimes99170a52007-12-19 02:07:34 +0000287# Beginning with Python 2.6 float has cross platform compatible
288# ways to create and representate inf and nan
289class InfNanTest(unittest.TestCase):
290 def test_inf_from_str(self):
291 self.assert_(isinf(float("inf")))
292 self.assert_(isinf(float("+inf")))
293 self.assert_(isinf(float("-inf")))
294
295 self.assertEqual(repr(float("inf")), "inf")
296 self.assertEqual(repr(float("+inf")), "inf")
297 self.assertEqual(repr(float("-inf")), "-inf")
298
299 self.assertEqual(repr(float("INF")), "inf")
300 self.assertEqual(repr(float("+Inf")), "inf")
301 self.assertEqual(repr(float("-iNF")), "-inf")
302
303 self.assertEqual(str(float("inf")), "inf")
304 self.assertEqual(str(float("+inf")), "inf")
305 self.assertEqual(str(float("-inf")), "-inf")
306
307 self.assertRaises(ValueError, float, "info")
308 self.assertRaises(ValueError, float, "+info")
309 self.assertRaises(ValueError, float, "-info")
310 self.assertRaises(ValueError, float, "in")
311 self.assertRaises(ValueError, float, "+in")
312 self.assertRaises(ValueError, float, "-in")
313
314 def test_inf_as_str(self):
315 self.assertEqual(repr(1e300 * 1e300), "inf")
316 self.assertEqual(repr(-1e300 * 1e300), "-inf")
317
318 self.assertEqual(str(1e300 * 1e300), "inf")
319 self.assertEqual(str(-1e300 * 1e300), "-inf")
320
321 def test_nan_from_str(self):
322 self.assert_(isnan(float("nan")))
323 self.assert_(isnan(float("+nan")))
324 self.assert_(isnan(float("-nan")))
325
326 self.assertEqual(repr(float("nan")), "nan")
327 self.assertEqual(repr(float("+nan")), "nan")
328 self.assertEqual(repr(float("-nan")), "nan")
329
330 self.assertEqual(repr(float("NAN")), "nan")
331 self.assertEqual(repr(float("+NAn")), "nan")
332 self.assertEqual(repr(float("-NaN")), "nan")
333
334 self.assertEqual(str(float("nan")), "nan")
335 self.assertEqual(str(float("+nan")), "nan")
336 self.assertEqual(str(float("-nan")), "nan")
337
338 self.assertRaises(ValueError, float, "nana")
339 self.assertRaises(ValueError, float, "+nana")
340 self.assertRaises(ValueError, float, "-nana")
341 self.assertRaises(ValueError, float, "na")
342 self.assertRaises(ValueError, float, "+na")
343 self.assertRaises(ValueError, float, "-na")
344
345 def test_nan_as_str(self):
346 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
347 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
348
349 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
350 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes827b35c2007-12-10 22:19:17 +0000351
Christian Heimes53876d92008-04-19 00:31:39 +0000352 def notest_float_nan(self):
353 self.assert_(NAN.is_nan())
354 self.failIf(INF.is_nan())
355 self.failIf((0.).is_nan())
356
357 def notest_float_inf(self):
358 self.assert_(INF.is_inf())
359 self.failIf(NAN.is_inf())
360 self.failIf((0.).is_inf())
361
362
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000363def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000364 support.run_unittest(
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000365 FormatFunctionsTestCase,
366 UnknownFormatTestCase,
Eric Smith8c663262007-08-25 02:26:07 +0000367 IEEEFormatTestCase,
Christian Heimes827b35c2007-12-10 22:19:17 +0000368 FormatTestCase,
Christian Heimes99170a52007-12-19 02:07:34 +0000369 ReprTestCase,
370 InfNanTest,
Christian Heimesb76922a2007-12-11 01:06:40 +0000371 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000372
373if __name__ == '__main__':
374 test_main()