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