mirror of
https://github.com/python/cpython.git
synced 2024-11-26 03:14:27 +08:00
53876d9cd8
svn+ssh://pythondev@svn.python.org/python/trunk ........ r62380 | christian.heimes | 2008-04-19 01:13:07 +0200 (Sat, 19 Apr 2008) | 3 lines I finally got the time to update and merge Mark's and my trunk-math branch. The patch is collaborated work of Mark Dickinson and me. It was mostly done a few months ago. The patch fixes a lot of loose ends and edge cases related to operations with NaN, INF, very small values and complex math. The patch also adds acosh, asinh, atanh, log1p and copysign to all platforms. Finally it fixes differences between platforms like different results or exceptions for edge cases. Have fun :) ........ r62382 | christian.heimes | 2008-04-19 01:40:40 +0200 (Sat, 19 Apr 2008) | 2 lines Added new files to Windows project files More Windows related fixes are coming soon ........ r62383 | christian.heimes | 2008-04-19 01:49:11 +0200 (Sat, 19 Apr 2008) | 1 line Stupid me. Py_RETURN_NAN should actually return something ... ........
265 lines
10 KiB
Python
265 lines
10 KiB
Python
|
|
import unittest, struct
|
|
import os
|
|
from test import test_support
|
|
import math
|
|
from math import isinf, isnan
|
|
import operator
|
|
|
|
INF = float("inf")
|
|
NAN = float("nan")
|
|
|
|
class FormatFunctionsTestCase(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.save_formats = {'double':float.__getformat__('double'),
|
|
'float':float.__getformat__('float')}
|
|
|
|
def tearDown(self):
|
|
float.__setformat__('double', self.save_formats['double'])
|
|
float.__setformat__('float', self.save_formats['float'])
|
|
|
|
def test_getformat(self):
|
|
self.assert_(float.__getformat__('double') in
|
|
['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
|
|
self.assert_(float.__getformat__('float') in
|
|
['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
|
|
self.assertRaises(ValueError, float.__getformat__, 'chicken')
|
|
self.assertRaises(TypeError, float.__getformat__, 1)
|
|
|
|
def test_setformat(self):
|
|
for t in 'double', 'float':
|
|
float.__setformat__(t, 'unknown')
|
|
if self.save_formats[t] == 'IEEE, big-endian':
|
|
self.assertRaises(ValueError, float.__setformat__,
|
|
t, 'IEEE, little-endian')
|
|
elif self.save_formats[t] == 'IEEE, little-endian':
|
|
self.assertRaises(ValueError, float.__setformat__,
|
|
t, 'IEEE, big-endian')
|
|
else:
|
|
self.assertRaises(ValueError, float.__setformat__,
|
|
t, 'IEEE, big-endian')
|
|
self.assertRaises(ValueError, float.__setformat__,
|
|
t, 'IEEE, little-endian')
|
|
self.assertRaises(ValueError, float.__setformat__,
|
|
t, 'chicken')
|
|
self.assertRaises(ValueError, float.__setformat__,
|
|
'chicken', 'unknown')
|
|
|
|
BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00'
|
|
LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF))
|
|
BE_DOUBLE_NAN = b'\x7f\xf8\x00\x00\x00\x00\x00\x00'
|
|
LE_DOUBLE_NAN = bytes(reversed(BE_DOUBLE_NAN))
|
|
|
|
BE_FLOAT_INF = b'\x7f\x80\x00\x00'
|
|
LE_FLOAT_INF = bytes(reversed(BE_FLOAT_INF))
|
|
BE_FLOAT_NAN = b'\x7f\xc0\x00\x00'
|
|
LE_FLOAT_NAN = bytes(reversed(BE_FLOAT_NAN))
|
|
|
|
# on non-IEEE platforms, attempting to unpack a bit pattern
|
|
# representing an infinity or a NaN should raise an exception.
|
|
|
|
class UnknownFormatTestCase(unittest.TestCase):
|
|
def setUp(self):
|
|
self.save_formats = {'double':float.__getformat__('double'),
|
|
'float':float.__getformat__('float')}
|
|
float.__setformat__('double', 'unknown')
|
|
float.__setformat__('float', 'unknown')
|
|
|
|
def tearDown(self):
|
|
float.__setformat__('double', self.save_formats['double'])
|
|
float.__setformat__('float', self.save_formats['float'])
|
|
|
|
def test_double_specials_dont_unpack(self):
|
|
for fmt, data in [('>d', BE_DOUBLE_INF),
|
|
('>d', BE_DOUBLE_NAN),
|
|
('<d', LE_DOUBLE_INF),
|
|
('<d', LE_DOUBLE_NAN)]:
|
|
self.assertRaises(ValueError, struct.unpack, fmt, data)
|
|
|
|
def test_float_specials_dont_unpack(self):
|
|
for fmt, data in [('>f', BE_FLOAT_INF),
|
|
('>f', BE_FLOAT_NAN),
|
|
('<f', LE_FLOAT_INF),
|
|
('<f', LE_FLOAT_NAN)]:
|
|
self.assertRaises(ValueError, struct.unpack, fmt, data)
|
|
|
|
|
|
# on an IEEE platform, all we guarantee is that bit patterns
|
|
# representing infinities or NaNs do not raise an exception; all else
|
|
# is accident (today).
|
|
# let's also try to guarantee that -0.0 and 0.0 don't get confused.
|
|
|
|
class IEEEFormatTestCase(unittest.TestCase):
|
|
if float.__getformat__("double").startswith("IEEE"):
|
|
def test_double_specials_do_unpack(self):
|
|
for fmt, data in [('>d', BE_DOUBLE_INF),
|
|
('>d', BE_DOUBLE_NAN),
|
|
('<d', LE_DOUBLE_INF),
|
|
('<d', LE_DOUBLE_NAN)]:
|
|
struct.unpack(fmt, data)
|
|
|
|
if float.__getformat__("float").startswith("IEEE"):
|
|
def test_float_specials_do_unpack(self):
|
|
for fmt, data in [('>f', BE_FLOAT_INF),
|
|
('>f', BE_FLOAT_NAN),
|
|
('<f', LE_FLOAT_INF),
|
|
('<f', LE_FLOAT_NAN)]:
|
|
struct.unpack(fmt, data)
|
|
|
|
if float.__getformat__("double").startswith("IEEE"):
|
|
def test_negative_zero(self):
|
|
import math
|
|
def pos_pos():
|
|
return 0.0, math.atan2(0.0, -1)
|
|
def pos_neg():
|
|
return 0.0, math.atan2(-0.0, -1)
|
|
def neg_pos():
|
|
return -0.0, math.atan2(0.0, -1)
|
|
def neg_neg():
|
|
return -0.0, math.atan2(-0.0, -1)
|
|
self.assertEquals(pos_pos(), neg_pos())
|
|
self.assertEquals(pos_neg(), neg_neg())
|
|
|
|
class FormatTestCase(unittest.TestCase):
|
|
def test_format(self):
|
|
# these should be rewritten to use both format(x, spec) and
|
|
# x.__format__(spec)
|
|
|
|
self.assertEqual(format(0.0, 'f'), '0.000000')
|
|
|
|
# the default is 'g', except for empty format spec
|
|
self.assertEqual(format(0.0, ''), '0.0')
|
|
self.assertEqual(format(0.01, ''), '0.01')
|
|
self.assertEqual(format(0.01, 'g'), '0.01')
|
|
|
|
|
|
self.assertEqual(format(1.0, 'f'), '1.000000')
|
|
|
|
self.assertEqual(format(-1.0, 'f'), '-1.000000')
|
|
|
|
self.assertEqual(format( 1.0, ' f'), ' 1.000000')
|
|
self.assertEqual(format(-1.0, ' f'), '-1.000000')
|
|
self.assertEqual(format( 1.0, '+f'), '+1.000000')
|
|
self.assertEqual(format(-1.0, '+f'), '-1.000000')
|
|
|
|
# % formatting
|
|
self.assertEqual(format(-1.0, '%'), '-100.000000%')
|
|
|
|
# conversion to string should fail
|
|
self.assertRaises(ValueError, format, 3.0, "s")
|
|
|
|
# other format specifiers shouldn't work on floats,
|
|
# in particular int specifiers
|
|
for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
|
|
[chr(x) for x in range(ord('A'), ord('Z')+1)]):
|
|
if not format_spec in 'eEfFgGn%':
|
|
self.assertRaises(ValueError, format, 0.0, format_spec)
|
|
self.assertRaises(ValueError, format, 1.0, format_spec)
|
|
self.assertRaises(ValueError, format, -1.0, format_spec)
|
|
self.assertRaises(ValueError, format, 1e100, format_spec)
|
|
self.assertRaises(ValueError, format, -1e100, format_spec)
|
|
self.assertRaises(ValueError, format, 1e-100, format_spec)
|
|
self.assertRaises(ValueError, format, -1e-100, format_spec)
|
|
|
|
class ReprTestCase(unittest.TestCase):
|
|
def test_repr(self):
|
|
floats_file = open(os.path.join(os.path.split(__file__)[0],
|
|
'floating_points.txt'))
|
|
for line in floats_file:
|
|
line = line.strip()
|
|
if not line or line.startswith('#'):
|
|
continue
|
|
v = eval(line)
|
|
self.assertEqual(v, eval(repr(v)))
|
|
floats_file.close()
|
|
|
|
# Beginning with Python 2.6 float has cross platform compatible
|
|
# ways to create and representate inf and nan
|
|
class InfNanTest(unittest.TestCase):
|
|
def test_inf_from_str(self):
|
|
self.assert_(isinf(float("inf")))
|
|
self.assert_(isinf(float("+inf")))
|
|
self.assert_(isinf(float("-inf")))
|
|
|
|
self.assertEqual(repr(float("inf")), "inf")
|
|
self.assertEqual(repr(float("+inf")), "inf")
|
|
self.assertEqual(repr(float("-inf")), "-inf")
|
|
|
|
self.assertEqual(repr(float("INF")), "inf")
|
|
self.assertEqual(repr(float("+Inf")), "inf")
|
|
self.assertEqual(repr(float("-iNF")), "-inf")
|
|
|
|
self.assertEqual(str(float("inf")), "inf")
|
|
self.assertEqual(str(float("+inf")), "inf")
|
|
self.assertEqual(str(float("-inf")), "-inf")
|
|
|
|
self.assertRaises(ValueError, float, "info")
|
|
self.assertRaises(ValueError, float, "+info")
|
|
self.assertRaises(ValueError, float, "-info")
|
|
self.assertRaises(ValueError, float, "in")
|
|
self.assertRaises(ValueError, float, "+in")
|
|
self.assertRaises(ValueError, float, "-in")
|
|
|
|
def test_inf_as_str(self):
|
|
self.assertEqual(repr(1e300 * 1e300), "inf")
|
|
self.assertEqual(repr(-1e300 * 1e300), "-inf")
|
|
|
|
self.assertEqual(str(1e300 * 1e300), "inf")
|
|
self.assertEqual(str(-1e300 * 1e300), "-inf")
|
|
|
|
def test_nan_from_str(self):
|
|
self.assert_(isnan(float("nan")))
|
|
self.assert_(isnan(float("+nan")))
|
|
self.assert_(isnan(float("-nan")))
|
|
|
|
self.assertEqual(repr(float("nan")), "nan")
|
|
self.assertEqual(repr(float("+nan")), "nan")
|
|
self.assertEqual(repr(float("-nan")), "nan")
|
|
|
|
self.assertEqual(repr(float("NAN")), "nan")
|
|
self.assertEqual(repr(float("+NAn")), "nan")
|
|
self.assertEqual(repr(float("-NaN")), "nan")
|
|
|
|
self.assertEqual(str(float("nan")), "nan")
|
|
self.assertEqual(str(float("+nan")), "nan")
|
|
self.assertEqual(str(float("-nan")), "nan")
|
|
|
|
self.assertRaises(ValueError, float, "nana")
|
|
self.assertRaises(ValueError, float, "+nana")
|
|
self.assertRaises(ValueError, float, "-nana")
|
|
self.assertRaises(ValueError, float, "na")
|
|
self.assertRaises(ValueError, float, "+na")
|
|
self.assertRaises(ValueError, float, "-na")
|
|
|
|
def test_nan_as_str(self):
|
|
self.assertEqual(repr(1e300 * 1e300 * 0), "nan")
|
|
self.assertEqual(repr(-1e300 * 1e300 * 0), "nan")
|
|
|
|
self.assertEqual(str(1e300 * 1e300 * 0), "nan")
|
|
self.assertEqual(str(-1e300 * 1e300 * 0), "nan")
|
|
|
|
def notest_float_nan(self):
|
|
self.assert_(NAN.is_nan())
|
|
self.failIf(INF.is_nan())
|
|
self.failIf((0.).is_nan())
|
|
|
|
def notest_float_inf(self):
|
|
self.assert_(INF.is_inf())
|
|
self.failIf(NAN.is_inf())
|
|
self.failIf((0.).is_inf())
|
|
|
|
|
|
def test_main():
|
|
test_support.run_unittest(
|
|
FormatFunctionsTestCase,
|
|
UnknownFormatTestCase,
|
|
IEEEFormatTestCase,
|
|
FormatTestCase,
|
|
ReprTestCase,
|
|
InfNanTest,
|
|
)
|
|
|
|
if __name__ == '__main__':
|
|
test_main()
|