blob: bb48df08324790a8a919f0efc7e0d6d51c011de2 [file] [log] [blame]
Michael W. Hudsonba283e22005-05-27 15:23:20 +00001
2import unittest, struct
Christian Heimes284d9272007-12-10 22:28:56 +00003import os
Michael W. Hudsonba283e22005-05-27 15:23:20 +00004from test import test_support
Christian Heimes6f341092008-04-18 23:13:07 +00005import math
6from math import isinf, isnan
7import operator
Michael W. Hudsonba283e22005-05-27 15:23:20 +00008
Christian Heimes6f341092008-04-18 23:13:07 +00009INF = float("inf")
10NAN = float("nan")
Christian Heimes0a8143f2007-12-18 23:22:54 +000011
Benjamin Peterson979395b2008-05-03 21:35:18 +000012class GeneralFloatCases(unittest.TestCase):
13
14 def test_float(self):
15 self.assertEqual(float(3.14), 3.14)
16 self.assertEqual(float(314), 314.0)
17 self.assertEqual(float(314L), 314.0)
18 self.assertEqual(float(" 3.14 "), 3.14)
19 self.assertRaises(ValueError, float, " 0x3.1 ")
20 self.assertRaises(ValueError, float, " -0x3.p-1 ")
21 self.assertRaises(ValueError, float, " +0x3.p-1 ")
22 self.assertRaises(ValueError, float, "++3.14")
23 self.assertRaises(ValueError, float, "+-3.14")
24 self.assertRaises(ValueError, float, "-+3.14")
25 self.assertRaises(ValueError, float, "--3.14")
26 if have_unicode:
27 self.assertEqual(float(unicode(" 3.14 ")), 3.14)
28 self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
29 # Implementation limitation in PyFloat_FromString()
30 self.assertRaises(ValueError, float, unicode("1"*10000))
31
32 @test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
33 def test_float_with_comma(self):
34 # set locale to something that doesn't use '.' for the decimal point
35 # float must not accept the locale specific decimal point but
36 # it still has to accept the normal python syntac
37 import locale
38 if not locale.localeconv()['decimal_point'] == ',':
39 return
40
41 self.assertEqual(float(" 3.14 "), 3.14)
42 self.assertEqual(float("+3.14 "), 3.14)
43 self.assertEqual(float("-3.14 "), -3.14)
44 self.assertEqual(float(".14 "), .14)
45 self.assertEqual(float("3. "), 3.0)
46 self.assertEqual(float("3.e3 "), 3000.0)
47 self.assertEqual(float("3.2e3 "), 3200.0)
48 self.assertEqual(float("2.5e-1 "), 0.25)
49 self.assertEqual(float("5e-1"), 0.5)
50 self.assertRaises(ValueError, float, " 3,14 ")
51 self.assertRaises(ValueError, float, " +3,14 ")
52 self.assertRaises(ValueError, float, " -3,14 ")
53 self.assertRaises(ValueError, float, " 0x3.1 ")
54 self.assertRaises(ValueError, float, " -0x3.p-1 ")
55 self.assertRaises(ValueError, float, " +0x3.p-1 ")
56 self.assertEqual(float(" 25.e-1 "), 2.5)
57 self.assertEqual(fcmp(float(" .25e-1 "), .025), 0)
58
59 def test_floatconversion(self):
60 # Make sure that calls to __float__() work properly
61 class Foo0:
62 def __float__(self):
63 return 42.
64
65 class Foo1(object):
66 def __float__(self):
67 return 42.
68
69 class Foo2(float):
70 def __float__(self):
71 return 42.
72
73 class Foo3(float):
74 def __new__(cls, value=0.):
75 return float.__new__(cls, 2*value)
76
77 def __float__(self):
78 return self
79
80 class Foo4(float):
81 def __float__(self):
82 return 42
83
84 self.assertAlmostEqual(float(Foo0()), 42.)
85 self.assertAlmostEqual(float(Foo1()), 42.)
86 self.assertAlmostEqual(float(Foo2()), 42.)
87 self.assertAlmostEqual(float(Foo3(21)), 42.)
88 self.assertRaises(TypeError, float, Foo4(42))
89
90 def test_floatasratio(self):
91 for f, ratio in [
92 (0.875, (7, 8)),
93 (-0.875, (-7, 8)),
94 (0.0, (0, 1)),
95 (11.5, (23, 2)),
96 ]:
97 self.assertEqual(f.as_integer_ratio(), ratio)
98
99 for i in range(10000):
100 f = random.random()
101 f *= 10 ** random.randint(-100, 100)
102 n, d = f.as_integer_ratio()
103 self.assertEqual(float(n).__truediv__(d), f)
104
105 R = fractions.Fraction
106 self.assertEqual(R(0, 1),
107 R(*float(0.0).as_integer_ratio()))
108 self.assertEqual(R(5, 2),
109 R(*float(2.5).as_integer_ratio()))
110 self.assertEqual(R(1, 2),
111 R(*float(0.5).as_integer_ratio()))
112 self.assertEqual(R(4728779608739021, 2251799813685248),
113 R(*float(2.1).as_integer_ratio()))
114 self.assertEqual(R(-4728779608739021, 2251799813685248),
115 R(*float(-2.1).as_integer_ratio()))
116 self.assertEqual(R(-2100, 1),
117 R(*float(-2100.0).as_integer_ratio()))
118
119 self.assertRaises(OverflowError, float('inf').as_integer_ratio)
120 self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
121 self.assertRaises(ValueError, float('nan').as_integer_ratio)
122
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000123class FormatFunctionsTestCase(unittest.TestCase):
124
125 def setUp(self):
126 self.save_formats = {'double':float.__getformat__('double'),
127 'float':float.__getformat__('float')}
128
129 def tearDown(self):
130 float.__setformat__('double', self.save_formats['double'])
131 float.__setformat__('float', self.save_formats['float'])
132
133 def test_getformat(self):
134 self.assert_(float.__getformat__('double') in
135 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
136 self.assert_(float.__getformat__('float') in
137 ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
138 self.assertRaises(ValueError, float.__getformat__, 'chicken')
139 self.assertRaises(TypeError, float.__getformat__, 1)
140
141 def test_setformat(self):
142 for t in 'double', 'float':
143 float.__setformat__(t, 'unknown')
144 if self.save_formats[t] == 'IEEE, big-endian':
145 self.assertRaises(ValueError, float.__setformat__,
146 t, 'IEEE, little-endian')
147 elif self.save_formats[t] == 'IEEE, little-endian':
148 self.assertRaises(ValueError, float.__setformat__,
149 t, 'IEEE, big-endian')
150 else:
151 self.assertRaises(ValueError, float.__setformat__,
152 t, 'IEEE, big-endian')
153 self.assertRaises(ValueError, float.__setformat__,
154 t, 'IEEE, little-endian')
155 self.assertRaises(ValueError, float.__setformat__,
156 t, 'chicken')
157 self.assertRaises(ValueError, float.__setformat__,
158 'chicken', 'unknown')
159
160BE_DOUBLE_INF = '\x7f\xf0\x00\x00\x00\x00\x00\x00'
161LE_DOUBLE_INF = ''.join(reversed(BE_DOUBLE_INF))
162BE_DOUBLE_NAN = '\x7f\xf8\x00\x00\x00\x00\x00\x00'
163LE_DOUBLE_NAN = ''.join(reversed(BE_DOUBLE_NAN))
164
165BE_FLOAT_INF = '\x7f\x80\x00\x00'
166LE_FLOAT_INF = ''.join(reversed(BE_FLOAT_INF))
167BE_FLOAT_NAN = '\x7f\xc0\x00\x00'
168LE_FLOAT_NAN = ''.join(reversed(BE_FLOAT_NAN))
169
170# on non-IEEE platforms, attempting to unpack a bit pattern
171# representing an infinity or a NaN should raise an exception.
172
173class UnknownFormatTestCase(unittest.TestCase):
174 def setUp(self):
175 self.save_formats = {'double':float.__getformat__('double'),
176 'float':float.__getformat__('float')}
177 float.__setformat__('double', 'unknown')
178 float.__setformat__('float', 'unknown')
Tim Peters5d36a552005-06-03 22:40:27 +0000179
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000180 def tearDown(self):
181 float.__setformat__('double', self.save_formats['double'])
182 float.__setformat__('float', self.save_formats['float'])
183
184 def test_double_specials_dont_unpack(self):
185 for fmt, data in [('>d', BE_DOUBLE_INF),
186 ('>d', BE_DOUBLE_NAN),
187 ('<d', LE_DOUBLE_INF),
188 ('<d', LE_DOUBLE_NAN)]:
189 self.assertRaises(ValueError, struct.unpack, fmt, data)
190
191 def test_float_specials_dont_unpack(self):
192 for fmt, data in [('>f', BE_FLOAT_INF),
193 ('>f', BE_FLOAT_NAN),
194 ('<f', LE_FLOAT_INF),
195 ('<f', LE_FLOAT_NAN)]:
196 self.assertRaises(ValueError, struct.unpack, fmt, data)
197
198
199# on an IEEE platform, all we guarantee is that bit patterns
200# representing infinities or NaNs do not raise an exception; all else
201# is accident (today).
Alex Martellid8672aa2007-08-22 21:14:17 +0000202# let's also try to guarantee that -0.0 and 0.0 don't get confused.
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000203
204class IEEEFormatTestCase(unittest.TestCase):
205 if float.__getformat__("double").startswith("IEEE"):
206 def test_double_specials_do_unpack(self):
207 for fmt, data in [('>d', BE_DOUBLE_INF),
208 ('>d', BE_DOUBLE_NAN),
209 ('<d', LE_DOUBLE_INF),
210 ('<d', LE_DOUBLE_NAN)]:
211 struct.unpack(fmt, data)
212
213 if float.__getformat__("float").startswith("IEEE"):
214 def test_float_specials_do_unpack(self):
215 for fmt, data in [('>f', BE_FLOAT_INF),
216 ('>f', BE_FLOAT_NAN),
217 ('<f', LE_FLOAT_INF),
218 ('<f', LE_FLOAT_NAN)]:
219 struct.unpack(fmt, data)
220
Alex Martellid8672aa2007-08-22 21:14:17 +0000221 if float.__getformat__("double").startswith("IEEE"):
222 def test_negative_zero(self):
223 import math
224 def pos_pos():
225 return 0.0, math.atan2(0.0, -1)
226 def pos_neg():
227 return 0.0, math.atan2(-0.0, -1)
228 def neg_pos():
229 return -0.0, math.atan2(0.0, -1)
230 def neg_neg():
231 return -0.0, math.atan2(-0.0, -1)
232 self.assertEquals(pos_pos(), neg_pos())
233 self.assertEquals(pos_neg(), neg_neg())
234
Guido van Rossum3b835492008-01-05 00:59:59 +0000235 if float.__getformat__("double").startswith("IEEE"):
236 def test_underflow_sign(self):
237 import math
238 # check that -1e-1000 gives -0.0, not 0.0
239 self.assertEquals(math.atan2(-1e-1000, -1), math.atan2(-0.0, -1))
240 self.assertEquals(math.atan2(float('-1e-1000'), -1),
241 math.atan2(-0.0, -1))
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000242
Christian Heimes284d9272007-12-10 22:28:56 +0000243class ReprTestCase(unittest.TestCase):
244 def test_repr(self):
245 floats_file = open(os.path.join(os.path.split(__file__)[0],
246 'floating_points.txt'))
247 for line in floats_file:
248 line = line.strip()
249 if not line or line.startswith('#'):
250 continue
251 v = eval(line)
252 self.assertEqual(v, eval(repr(v)))
253 floats_file.close()
254
Christian Heimes0a8143f2007-12-18 23:22:54 +0000255# Beginning with Python 2.6 float has cross platform compatible
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000256# ways to create and represent inf and nan
Christian Heimes0a8143f2007-12-18 23:22:54 +0000257class InfNanTest(unittest.TestCase):
258 def test_inf_from_str(self):
259 self.assert_(isinf(float("inf")))
260 self.assert_(isinf(float("+inf")))
261 self.assert_(isinf(float("-inf")))
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000262 self.assert_(isinf(float("infinity")))
263 self.assert_(isinf(float("+infinity")))
264 self.assert_(isinf(float("-infinity")))
Christian Heimes0a8143f2007-12-18 23:22:54 +0000265
266 self.assertEqual(repr(float("inf")), "inf")
267 self.assertEqual(repr(float("+inf")), "inf")
268 self.assertEqual(repr(float("-inf")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000269 self.assertEqual(repr(float("infinity")), "inf")
270 self.assertEqual(repr(float("+infinity")), "inf")
271 self.assertEqual(repr(float("-infinity")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000272
273 self.assertEqual(repr(float("INF")), "inf")
274 self.assertEqual(repr(float("+Inf")), "inf")
275 self.assertEqual(repr(float("-iNF")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000276 self.assertEqual(repr(float("Infinity")), "inf")
277 self.assertEqual(repr(float("+iNfInItY")), "inf")
278 self.assertEqual(repr(float("-INFINITY")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000279
280 self.assertEqual(str(float("inf")), "inf")
281 self.assertEqual(str(float("+inf")), "inf")
282 self.assertEqual(str(float("-inf")), "-inf")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000283 self.assertEqual(str(float("infinity")), "inf")
284 self.assertEqual(str(float("+infinity")), "inf")
285 self.assertEqual(str(float("-infinity")), "-inf")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000286
287 self.assertRaises(ValueError, float, "info")
288 self.assertRaises(ValueError, float, "+info")
289 self.assertRaises(ValueError, float, "-info")
290 self.assertRaises(ValueError, float, "in")
291 self.assertRaises(ValueError, float, "+in")
292 self.assertRaises(ValueError, float, "-in")
Mark Dickinsonbf9f4d82008-07-05 11:33:52 +0000293 self.assertRaises(ValueError, float, "infinit")
294 self.assertRaises(ValueError, float, "+Infin")
295 self.assertRaises(ValueError, float, "-INFI")
296 self.assertRaises(ValueError, float, "infinitys")
Christian Heimes0a8143f2007-12-18 23:22:54 +0000297
298 def test_inf_as_str(self):
299 self.assertEqual(repr(1e300 * 1e300), "inf")
300 self.assertEqual(repr(-1e300 * 1e300), "-inf")
301
302 self.assertEqual(str(1e300 * 1e300), "inf")
303 self.assertEqual(str(-1e300 * 1e300), "-inf")
304
305 def test_nan_from_str(self):
306 self.assert_(isnan(float("nan")))
307 self.assert_(isnan(float("+nan")))
308 self.assert_(isnan(float("-nan")))
309
310 self.assertEqual(repr(float("nan")), "nan")
311 self.assertEqual(repr(float("+nan")), "nan")
312 self.assertEqual(repr(float("-nan")), "nan")
313
314 self.assertEqual(repr(float("NAN")), "nan")
315 self.assertEqual(repr(float("+NAn")), "nan")
316 self.assertEqual(repr(float("-NaN")), "nan")
317
318 self.assertEqual(str(float("nan")), "nan")
319 self.assertEqual(str(float("+nan")), "nan")
320 self.assertEqual(str(float("-nan")), "nan")
321
322 self.assertRaises(ValueError, float, "nana")
323 self.assertRaises(ValueError, float, "+nana")
324 self.assertRaises(ValueError, float, "-nana")
325 self.assertRaises(ValueError, float, "na")
326 self.assertRaises(ValueError, float, "+na")
327 self.assertRaises(ValueError, float, "-na")
328
329 def test_nan_as_str(self):
330 self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
331 self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
332
333 self.assertEqual(str(1e300 * 1e300 * 0), "nan")
334 self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
Christian Heimes284d9272007-12-10 22:28:56 +0000335
Christian Heimes6f341092008-04-18 23:13:07 +0000336 def notest_float_nan(self):
337 self.assert_(NAN.is_nan())
338 self.failIf(INF.is_nan())
339 self.failIf((0.).is_nan())
340
341 def notest_float_inf(self):
342 self.assert_(INF.is_inf())
343 self.failIf(NAN.is_inf())
344 self.failIf((0.).is_inf())
345
346
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000347def test_main():
348 test_support.run_unittest(
349 FormatFunctionsTestCase,
350 UnknownFormatTestCase,
Christian Heimes284d9272007-12-10 22:28:56 +0000351 IEEEFormatTestCase,
Christian Heimes0a8143f2007-12-18 23:22:54 +0000352 ReprTestCase,
353 InfNanTest,
Christian Heimesf15c66e2007-12-11 00:54:34 +0000354 )
Michael W. Hudsonba283e22005-05-27 15:23:20 +0000355
356if __name__ == '__main__':
357 test_main()