summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_float.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_float.py')
-rw-r--r--Lib/test/test_float.py443
1 files changed, 286 insertions, 157 deletions
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index 2b250df..1968b8a 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -7,7 +7,6 @@ import math
from math import isinf, isnan, copysign, ldexp
import operator
import random, fractions
-import re
INF = float("inf")
NAN = float("nan")
@@ -17,83 +16,11 @@ requires_getformat = unittest.skipUnless(have_getformat,
"requires __getformat__")
requires_setformat = unittest.skipUnless(hasattr(float, "__setformat__"),
"requires __setformat__")
-# decorator for skipping tests on non-IEEE 754 platforms
-requires_IEEE_754 = unittest.skipUnless(have_getformat and
- float.__getformat__("double").startswith("IEEE"),
- "test requires IEEE 754 doubles")
#locate file with float format test values
test_dir = os.path.dirname(__file__) or os.curdir
format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
-finite_decimal_parser = re.compile(r""" # A numeric string consists of:
- (?P<sign>[-+])? # an optional sign, followed by
- (?=\d|\.\d) # a number with at least one digit
- (?P<int>\d*) # having a (possibly empty) integer part
- (?:\.(?P<frac>\d*))? # followed by an optional fractional part
- (?:E(?P<exp>[-+]?\d+))? # and an optional exponent
- \Z
-""", re.VERBOSE | re.IGNORECASE | re.UNICODE).match
-
-# Pure Python version of correctly rounded string->float conversion.
-# Avoids any use of floating-point by returning the result as a hex string.
-def strtod(s, mant_dig=53, min_exp = -1021, max_exp = 1024):
- """Convert a finite decimal string to a hex string representing an
- IEEE 754 binary64 float. Return 'inf' or '-inf' on overflow.
- This function makes no use of floating-point arithmetic at any
- stage."""
-
- # parse string into a pair of integers 'a' and 'b' such that
- # abs(decimal value) = a/b, and a boolean 'negative'.
- m = finite_decimal_parser(s)
- if m is None:
- raise ValueError('invalid numeric string')
- fraction = m.group('frac') or ''
- intpart = int(m.group('int') + fraction)
- exp = int(m.group('exp') or '0') - len(fraction)
- negative = m.group('sign') == '-'
- a, b = intpart*10**max(exp, 0), 10**max(0, -exp)
-
- # quick return for zeros
- if not a:
- return '-0x0.0p+0' if negative else '0x0.0p+0'
-
- # compute exponent e for result; may be one too small in the case
- # that the rounded value of a/b lies in a different binade from a/b
- d = a.bit_length() - b.bit_length()
- d += (a >> d if d >= 0 else a << -d) >= b
- e = max(d, min_exp) - mant_dig
-
- # approximate a/b by number of the form q * 2**e; adjust e if necessary
- a, b = a << max(-e, 0), b << max(e, 0)
- q, r = divmod(a, b)
- if 2*r > b or 2*r == b and q & 1:
- q += 1
- if q.bit_length() == mant_dig+1:
- q //= 2
- e += 1
-
- # double check that (q, e) has the right form
- assert q.bit_length() <= mant_dig and e >= min_exp - mant_dig
- assert q.bit_length() == mant_dig or e == min_exp - mant_dig
-
- # check for overflow and underflow
- if e + q.bit_length() > max_exp:
- return '-inf' if negative else 'inf'
- if not q:
- return '-0x0.0p+0' if negative else '0x0.0p+0'
-
- # for hex representation, shift so # bits after point is a multiple of 4
- hexdigs = 1 + (mant_dig-2)//4
- shift = 3 - (mant_dig-2)%4
- q, e = q << shift, e - shift
- return '{}0x{:x}.{:0{}x}p{:+d}'.format(
- '-' if negative else '',
- q // 16**hexdigs,
- q % 16**hexdigs,
- hexdigs,
- e + 4*hexdigs)
-
class GeneralFloatCases(unittest.TestCase):
def test_float(self):
@@ -112,11 +39,30 @@ class GeneralFloatCases(unittest.TestCase):
self.assertRaises(ValueError, float, "+.inf")
self.assertRaises(ValueError, float, ".")
self.assertRaises(ValueError, float, "-.")
- self.assertEqual(float(b" \u0663.\u0661\u0664 ".decode('raw-unicode-escape')), 3.14)
+ self.assertRaises(ValueError, float, b"-")
+ self.assertRaises(TypeError, float, {})
+ # Lone surrogate
+ self.assertRaises(UnicodeEncodeError, float, '\uD8F0')
+ # check that we don't accept alternate exponent markers
+ self.assertRaises(ValueError, float, "-1.7d29")
+ self.assertRaises(ValueError, float, "3D-14")
+ self.assertEqual(float(" \u0663.\u0661\u0664 "), 3.14)
+ self.assertEqual(float("\N{EM SPACE}3.14\N{EN SPACE}"), 3.14)
# extra long strings should not be a problem
float(b'.' + b'1'*1000)
float('.' + '1'*1000)
+ def test_error_message(self):
+ testlist = ('\xbd', '123\xbd', ' 123 456 ')
+ for s in testlist:
+ try:
+ float(s)
+ except ValueError as e:
+ self.assertIn(s.strip(), e.args[0])
+ else:
+ self.fail("Expected int(%r) to raise a ValueError", s)
+
+
@support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
def test_float_with_comma(self):
# set locale to something that doesn't use '.' for the decimal point
@@ -218,12 +164,12 @@ class GeneralFloatCases(unittest.TestCase):
def test_float_containment(self):
floats = (INF, -INF, 0.0, 1.0, NAN)
for f in floats:
- self.assertTrue(f in [f], "'%r' not in []" % f)
- self.assertTrue(f in (f,), "'%r' not in ()" % f)
- self.assertTrue(f in {f}, "'%r' not in set()" % f)
- self.assertTrue(f in {f: None}, "'%r' not in {}" % f)
+ self.assertIn(f, [f])
+ self.assertIn(f, (f,))
+ self.assertIn(f, {f})
+ self.assertIn(f, {f: None})
self.assertEqual([f].count(f), 1, "[].count('%r') != 1" % f)
- self.assertTrue(f in floats, "'%r' not in container" % f)
+ self.assertIn(f, floats)
for f in floats:
# nonidentical containers, same type, same contents
@@ -246,7 +192,7 @@ class GeneralFloatCases(unittest.TestCase):
# distinguishes -0.0 and 0.0.
self.assertEqual((a, copysign(1.0, a)), (b, copysign(1.0, b)))
- @requires_IEEE_754
+ @support.requires_IEEE_754
def test_float_mod(self):
# Check behaviour of % operator for IEEE 754 special cases.
# In particular, check signs of zeros.
@@ -266,7 +212,209 @@ class GeneralFloatCases(unittest.TestCase):
self.assertEqualAndEqualSign(mod(1e-100, -1.0), -1.0)
self.assertEqualAndEqualSign(mod(1.0, -1.0), -0.0)
-
+ @support.requires_IEEE_754
+ def test_float_pow(self):
+ # test builtin pow and ** operator for IEEE 754 special cases.
+ # Special cases taken from section F.9.4.4 of the C99 specification
+
+ for pow_op in pow, operator.pow:
+ # x**NAN is NAN for any x except 1
+ self.assertTrue(isnan(pow_op(-INF, NAN)))
+ self.assertTrue(isnan(pow_op(-2.0, NAN)))
+ self.assertTrue(isnan(pow_op(-1.0, NAN)))
+ self.assertTrue(isnan(pow_op(-0.5, NAN)))
+ self.assertTrue(isnan(pow_op(-0.0, NAN)))
+ self.assertTrue(isnan(pow_op(0.0, NAN)))
+ self.assertTrue(isnan(pow_op(0.5, NAN)))
+ self.assertTrue(isnan(pow_op(2.0, NAN)))
+ self.assertTrue(isnan(pow_op(INF, NAN)))
+ self.assertTrue(isnan(pow_op(NAN, NAN)))
+
+ # NAN**y is NAN for any y except +-0
+ self.assertTrue(isnan(pow_op(NAN, -INF)))
+ self.assertTrue(isnan(pow_op(NAN, -2.0)))
+ self.assertTrue(isnan(pow_op(NAN, -1.0)))
+ self.assertTrue(isnan(pow_op(NAN, -0.5)))
+ self.assertTrue(isnan(pow_op(NAN, 0.5)))
+ self.assertTrue(isnan(pow_op(NAN, 1.0)))
+ self.assertTrue(isnan(pow_op(NAN, 2.0)))
+ self.assertTrue(isnan(pow_op(NAN, INF)))
+
+ # (+-0)**y raises ZeroDivisionError for y a negative odd integer
+ self.assertRaises(ZeroDivisionError, pow_op, -0.0, -1.0)
+ self.assertRaises(ZeroDivisionError, pow_op, 0.0, -1.0)
+
+ # (+-0)**y raises ZeroDivisionError for y finite and negative
+ # but not an odd integer
+ self.assertRaises(ZeroDivisionError, pow_op, -0.0, -2.0)
+ self.assertRaises(ZeroDivisionError, pow_op, -0.0, -0.5)
+ self.assertRaises(ZeroDivisionError, pow_op, 0.0, -2.0)
+ self.assertRaises(ZeroDivisionError, pow_op, 0.0, -0.5)
+
+ # (+-0)**y is +-0 for y a positive odd integer
+ self.assertEqualAndEqualSign(pow_op(-0.0, 1.0), -0.0)
+ self.assertEqualAndEqualSign(pow_op(0.0, 1.0), 0.0)
+
+ # (+-0)**y is 0 for y finite and positive but not an odd integer
+ self.assertEqualAndEqualSign(pow_op(-0.0, 0.5), 0.0)
+ self.assertEqualAndEqualSign(pow_op(-0.0, 2.0), 0.0)
+ self.assertEqualAndEqualSign(pow_op(0.0, 0.5), 0.0)
+ self.assertEqualAndEqualSign(pow_op(0.0, 2.0), 0.0)
+
+ # (-1)**+-inf is 1
+ self.assertEqualAndEqualSign(pow_op(-1.0, -INF), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, INF), 1.0)
+
+ # 1**y is 1 for any y, even if y is an infinity or nan
+ self.assertEqualAndEqualSign(pow_op(1.0, -INF), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, -2.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, -1.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, -0.5), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, 0.5), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, 1.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, 2.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, INF), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, NAN), 1.0)
+
+ # x**+-0 is 1 for any x, even if x is a zero, infinity, or nan
+ self.assertEqualAndEqualSign(pow_op(-INF, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-2.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-0.5, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-0.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(0.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(0.5, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(INF, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(NAN, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-INF, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-2.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-0.5, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-0.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(0.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(0.5, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(INF, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(NAN, -0.0), 1.0)
+
+ # x**y defers to complex pow for finite negative x and
+ # non-integral y.
+ self.assertEqual(type(pow_op(-2.0, -0.5)), complex)
+ self.assertEqual(type(pow_op(-2.0, 0.5)), complex)
+ self.assertEqual(type(pow_op(-1.0, -0.5)), complex)
+ self.assertEqual(type(pow_op(-1.0, 0.5)), complex)
+ self.assertEqual(type(pow_op(-0.5, -0.5)), complex)
+ self.assertEqual(type(pow_op(-0.5, 0.5)), complex)
+
+ # x**-INF is INF for abs(x) < 1
+ self.assertEqualAndEqualSign(pow_op(-0.5, -INF), INF)
+ self.assertEqualAndEqualSign(pow_op(-0.0, -INF), INF)
+ self.assertEqualAndEqualSign(pow_op(0.0, -INF), INF)
+ self.assertEqualAndEqualSign(pow_op(0.5, -INF), INF)
+
+ # x**-INF is 0 for abs(x) > 1
+ self.assertEqualAndEqualSign(pow_op(-INF, -INF), 0.0)
+ self.assertEqualAndEqualSign(pow_op(-2.0, -INF), 0.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, -INF), 0.0)
+ self.assertEqualAndEqualSign(pow_op(INF, -INF), 0.0)
+
+ # x**INF is 0 for abs(x) < 1
+ self.assertEqualAndEqualSign(pow_op(-0.5, INF), 0.0)
+ self.assertEqualAndEqualSign(pow_op(-0.0, INF), 0.0)
+ self.assertEqualAndEqualSign(pow_op(0.0, INF), 0.0)
+ self.assertEqualAndEqualSign(pow_op(0.5, INF), 0.0)
+
+ # x**INF is INF for abs(x) > 1
+ self.assertEqualAndEqualSign(pow_op(-INF, INF), INF)
+ self.assertEqualAndEqualSign(pow_op(-2.0, INF), INF)
+ self.assertEqualAndEqualSign(pow_op(2.0, INF), INF)
+ self.assertEqualAndEqualSign(pow_op(INF, INF), INF)
+
+ # (-INF)**y is -0.0 for y a negative odd integer
+ self.assertEqualAndEqualSign(pow_op(-INF, -1.0), -0.0)
+
+ # (-INF)**y is 0.0 for y negative but not an odd integer
+ self.assertEqualAndEqualSign(pow_op(-INF, -0.5), 0.0)
+ self.assertEqualAndEqualSign(pow_op(-INF, -2.0), 0.0)
+
+ # (-INF)**y is -INF for y a positive odd integer
+ self.assertEqualAndEqualSign(pow_op(-INF, 1.0), -INF)
+
+ # (-INF)**y is INF for y positive but not an odd integer
+ self.assertEqualAndEqualSign(pow_op(-INF, 0.5), INF)
+ self.assertEqualAndEqualSign(pow_op(-INF, 2.0), INF)
+
+ # INF**y is INF for y positive
+ self.assertEqualAndEqualSign(pow_op(INF, 0.5), INF)
+ self.assertEqualAndEqualSign(pow_op(INF, 1.0), INF)
+ self.assertEqualAndEqualSign(pow_op(INF, 2.0), INF)
+
+ # INF**y is 0.0 for y negative
+ self.assertEqualAndEqualSign(pow_op(INF, -2.0), 0.0)
+ self.assertEqualAndEqualSign(pow_op(INF, -1.0), 0.0)
+ self.assertEqualAndEqualSign(pow_op(INF, -0.5), 0.0)
+
+ # basic checks not covered by the special cases above
+ self.assertEqualAndEqualSign(pow_op(-2.0, -2.0), 0.25)
+ self.assertEqualAndEqualSign(pow_op(-2.0, -1.0), -0.5)
+ self.assertEqualAndEqualSign(pow_op(-2.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-2.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-2.0, 1.0), -2.0)
+ self.assertEqualAndEqualSign(pow_op(-2.0, 2.0), 4.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, -2.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, -1.0), -1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, 1.0), -1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, 2.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, -2.0), 0.25)
+ self.assertEqualAndEqualSign(pow_op(2.0, -1.0), 0.5)
+ self.assertEqualAndEqualSign(pow_op(2.0, -0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, 0.0), 1.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, 1.0), 2.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, 2.0), 4.0)
+
+ # 1 ** large and -1 ** large; some libms apparently
+ # have problems with these
+ self.assertEqualAndEqualSign(pow_op(1.0, -1e100), 1.0)
+ self.assertEqualAndEqualSign(pow_op(1.0, 1e100), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, -1e100), 1.0)
+ self.assertEqualAndEqualSign(pow_op(-1.0, 1e100), 1.0)
+
+ # check sign for results that underflow to 0
+ self.assertEqualAndEqualSign(pow_op(-2.0, -2000.0), 0.0)
+ self.assertEqual(type(pow_op(-2.0, -2000.5)), complex)
+ self.assertEqualAndEqualSign(pow_op(-2.0, -2001.0), -0.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, -2000.0), 0.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, -2000.5), 0.0)
+ self.assertEqualAndEqualSign(pow_op(2.0, -2001.0), 0.0)
+ self.assertEqualAndEqualSign(pow_op(-0.5, 2000.0), 0.0)
+ self.assertEqual(type(pow_op(-0.5, 2000.5)), complex)
+ self.assertEqualAndEqualSign(pow_op(-0.5, 2001.0), -0.0)
+ self.assertEqualAndEqualSign(pow_op(0.5, 2000.0), 0.0)
+ self.assertEqualAndEqualSign(pow_op(0.5, 2000.5), 0.0)
+ self.assertEqualAndEqualSign(pow_op(0.5, 2001.0), 0.0)
+
+ # check we don't raise an exception for subnormal results,
+ # and validate signs. Tests currently disabled, since
+ # they fail on systems where a subnormal result from pow
+ # is flushed to zero (e.g. Debian/ia64.)
+ #self.assertTrue(0.0 < pow_op(0.5, 1048) < 1e-315)
+ #self.assertTrue(0.0 < pow_op(-0.5, 1048) < 1e-315)
+ #self.assertTrue(0.0 < pow_op(0.5, 1047) < 1e-315)
+ #self.assertTrue(0.0 > pow_op(-0.5, 1047) > -1e-315)
+ #self.assertTrue(0.0 < pow_op(2.0, -1048) < 1e-315)
+ #self.assertTrue(0.0 < pow_op(-2.0, -1048) < 1e-315)
+ #self.assertTrue(0.0 < pow_op(2.0, -1047) < 1e-315)
+ #self.assertTrue(0.0 > pow_op(-2.0, -1047) > -1e-315)
+
+
+@requires_setformat
class FormatFunctionsTestCase(unittest.TestCase):
def setUp(self):
@@ -278,10 +426,10 @@ class FormatFunctionsTestCase(unittest.TestCase):
float.__setformat__('float', self.save_formats['float'])
def test_getformat(self):
- self.assertTrue(float.__getformat__('double') in
- ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
- self.assertTrue(float.__getformat__('float') in
- ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
+ self.assertIn(float.__getformat__('double'),
+ ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
+ self.assertIn(float.__getformat__('float'),
+ ['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
self.assertRaises(ValueError, float.__getformat__, 'chicken')
self.assertRaises(TypeError, float.__getformat__, 1)
@@ -317,6 +465,7 @@ 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.
+@requires_setformat
class UnknownFormatTestCase(unittest.TestCase):
def setUp(self):
self.save_formats = {'double':float.__getformat__('double'),
@@ -349,37 +498,25 @@ class UnknownFormatTestCase(unittest.TestCase):
# 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.assertEqual(pos_pos(), neg_pos())
- self.assertEqual(pos_neg(), neg_neg())
+
+ @support.requires_IEEE_754
+ 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)
+
+ @support.requires_IEEE_754
+ 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)
class FormatTestCase(unittest.TestCase):
+
def test_format(self):
# these should be rewritten to use both format(x, spec) and
# x.__format__(spec)
@@ -433,8 +570,7 @@ class FormatTestCase(unittest.TestCase):
self.assertEqual(format(INF, 'f'), 'inf')
self.assertEqual(format(INF, 'F'), 'INF')
- @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
- "test requires IEEE 754 doubles")
+ @support.requires_IEEE_754
def test_format_testfile(self):
with open(format_testfile) as testfile:
for line in testfile:
@@ -514,10 +650,13 @@ class ReprTestCase(unittest.TestCase):
negs = '-'+s
self.assertEqual(s, repr(float(s)))
self.assertEqual(negs, repr(float(negs)))
+ # Since Python 3.2, repr and str are identical
+ self.assertEqual(repr(float(s)), str(float(s)))
+ self.assertEqual(repr(float(negs)), str(float(negs)))
+@support.requires_IEEE_754
class RoundTestCase(unittest.TestCase):
- @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
- "test requires IEEE 754 doubles")
+
def test_inf_nan(self):
self.assertRaises(OverflowError, round, INF)
self.assertRaises(OverflowError, round, -INF)
@@ -527,8 +666,6 @@ class RoundTestCase(unittest.TestCase):
self.assertRaises(TypeError, round, NAN, "ceci n'est pas un integer")
self.assertRaises(TypeError, round, -0.0, 1j)
- @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
- "test requires IEEE 754 doubles")
def test_large_n(self):
for n in [324, 325, 400, 2**31-1, 2**31, 2**32, 2**100]:
self.assertEqual(round(123.456, n), 123.456)
@@ -541,8 +678,6 @@ class RoundTestCase(unittest.TestCase):
self.assertEqual(round(1e150, 309), 1e150)
self.assertEqual(round(1.4e-315, 315), 1e-315)
- @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
- "test requires IEEE 754 doubles")
def test_small_n(self):
for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]:
self.assertEqual(round(123.456, n), 0.0)
@@ -550,8 +685,6 @@ class RoundTestCase(unittest.TestCase):
self.assertEqual(round(1e300, n), 0.0)
self.assertEqual(round(1e-320, n), 0.0)
- @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
- "test requires IEEE 754 doubles")
def test_overflow(self):
self.assertRaises(OverflowError, round, 1.6e308, -308)
self.assertRaises(OverflowError, round, -1.7e308, -308)
@@ -599,6 +732,35 @@ class RoundTestCase(unittest.TestCase):
self.assertEqual(float(format(x, '.2f')), round(x, 2))
self.assertEqual(float(format(x, '.3f')), round(x, 3))
+ def test_format_specials(self):
+ # Test formatting of nans and infs.
+
+ def test(fmt, value, expected):
+ # Test with both % and format().
+ self.assertEqual(fmt % value, expected, fmt)
+ fmt = fmt[1:] # strip off the %
+ self.assertEqual(format(value, fmt), expected, fmt)
+
+ for fmt in ['%e', '%f', '%g', '%.0e', '%.6f', '%.20g',
+ '%#e', '%#f', '%#g', '%#.20e', '%#.15f', '%#.3g']:
+ pfmt = '%+' + fmt[1:]
+ sfmt = '% ' + fmt[1:]
+ test(fmt, INF, 'inf')
+ test(fmt, -INF, '-inf')
+ test(fmt, NAN, 'nan')
+ test(fmt, -NAN, 'nan')
+ # When asking for a sign, it's always provided. nans are
+ # always positive.
+ test(pfmt, INF, '+inf')
+ test(pfmt, -INF, '-inf')
+ test(pfmt, NAN, '+nan')
+ test(pfmt, -NAN, '+nan')
+ # When using ' ' for a sign code, only infs can be negative.
+ # Others have a space.
+ test(sfmt, INF, ' inf')
+ test(sfmt, -INF, '-inf')
+ test(sfmt, NAN, ' nan')
+ test(sfmt, -NAN, ' nan')
# Beginning with Python 2.6 float has cross platform compatible
@@ -1122,38 +1284,6 @@ class HexFloatTestCase(unittest.TestCase):
else:
self.identical(x, fromHex(toHex(x)))
-class StrtodTestCase(unittest.TestCase):
- def check_string(self, s):
- expected = strtod(s)
- try:
- fs = float(s)
- except OverflowError:
- got = '-inf' if s[0] == '-' else 'inf'
- else:
- got = fs.hex()
- self.assertEqual(expected, got,
- "Incorrectly rounded str->float conversion for "
- "{}: expected {}, got {}".format(s, expected, got))
-
- @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
- "applies only when using short float repr style")
- def test_bug7632(self):
- # check a few particular values that gave incorrectly rounded
- # results with previous versions of dtoa.c
- test_strings = [
- '94393431193180696942841837085033647913224148539854e-358',
- '12579816049008305546974391768996369464963024663104e-357',
- '17489628565202117263145367596028389348922981857013e-357',
- '18487398785991994634182916638542680759613590482273e-357',
- '32002864200581033134358724675198044527469366773928e-358',
- '73608278998966969345824653500136787876436005957953e-358',
- '64774478836417299491718435234611299336288082136054e-358',
- '13704940134126574534878641876947980878824688451169e-357',
- '46697445774047060960624497964425416610480524760471e-358',
- ]
- for s in test_strings:
- self.check_string(s)
-
def test_main():
support.run_unittest(
@@ -1166,7 +1296,6 @@ def test_main():
RoundTestCase,
InfNanTest,
HexFloatTestCase,
- StrtodTestCase,
)
if __name__ == '__main__':