diff options
author | Eric Smith <eric@trueblade.com> | 2009-04-16 20:16:10 (GMT) |
---|---|---|
committer | Eric Smith <eric@trueblade.com> | 2009-04-16 20:16:10 (GMT) |
commit | 0923d1d8d7e428297461ed5145f06915c462b25b (patch) | |
tree | b1fee964b1030c99285ae9d95e7e4dfb60dcded0 /Lib | |
parent | b08a53a99def3fa949643974f713b5b189e21bc7 (diff) | |
download | cpython-0923d1d8d7e428297461ed5145f06915c462b25b.zip cpython-0923d1d8d7e428297461ed5145f06915c462b25b.tar.gz cpython-0923d1d8d7e428297461ed5145f06915c462b25b.tar.bz2 |
The other half of Issue #1580: use short float repr where possible.
Addresses the float -> string conversion, using David Gay's code which
was added in Mark Dickinson's checkin r71663.
Also addresses these, which are intertwined with the short repr
changes:
- Issue #5772: format(1e100, '<') produces '1e+100', not '1.0e+100'
- Issue #5515: 'n' formatting with commas no longer works poorly
with leading zeros.
- PEP 378 Format Specifier for Thousands Separator: implemented
for floats.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_float.py | 76 | ||||
-rw-r--r-- | Lib/test/test_format.py | 5 | ||||
-rw-r--r-- | Lib/test/test_types.py | 49 |
3 files changed, 129 insertions, 1 deletions
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index 123a69d..8c250e8 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -1,6 +1,7 @@ import unittest, struct import os +import sys from test import support import math from math import isinf, isnan, copysign, ldexp @@ -10,6 +11,10 @@ import random, fractions INF = float("inf") NAN = float("nan") +#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') + class GeneralFloatCases(unittest.TestCase): def test_float(self): @@ -24,6 +29,10 @@ class GeneralFloatCases(unittest.TestCase): self.assertRaises(ValueError, float, "+-3.14") self.assertRaises(ValueError, float, "-+3.14") self.assertRaises(ValueError, float, "--3.14") + self.assertRaises(ValueError, float, ".nan") + 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) @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE') @@ -316,6 +325,73 @@ class ReprTestCase(unittest.TestCase): self.assertEqual(v, eval(repr(v))) floats_file.close() +class FormatTestCase(unittest.TestCase): + @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), + "test requires IEEE 754 doubles") + def test_format_testfile(self): + for line in open(format_testfile): + if line.startswith('--'): + continue + line = line.strip() + if not line: + continue + + lhs, rhs = map(str.strip, line.split('->')) + fmt, arg = lhs.split() + self.assertEqual(fmt % float(arg), rhs) + self.assertEqual(fmt % -float(arg), '-' + rhs) + + @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short', + "applies only when using short float repr style") + def test_short_repr(self): + # test short float repr introduced in Python 3.1. One aspect + # of this repr is that we get some degree of str -> float -> + # str roundtripping. In particular, for any numeric string + # containing 15 or fewer significant digits, those exact same + # digits (modulo trailing zeros) should appear in the output. + # No more repr(0.03) -> "0.029999999999999999"! + + test_strings = [ + # output always includes *either* a decimal point and at + # least one digit after that point, or an exponent. + '0.0', + '1.0', + '0.01', + '0.02', + '0.03', + '0.04', + '0.05', + '1.23456789', + '10.0', + '100.0', + # values >= 1e16 get an exponent... + '1000000000000000.0', + '9999999999999990.0', + '1e+16', + '1e+17', + # ... and so do values < 1e-4 + '0.001', + '0.001001', + '0.00010000000000001', + '0.0001', + '9.999999999999e-05', + '1e-05', + # values designed to provoke failure if the FPU rounding + # precision isn't set correctly + '8.72293771110361e+25', + '7.47005307342313e+26', + '2.86438000439698e+28', + '8.89142905246179e+28', + '3.08578087079232e+35', + ] + + for s in test_strings: + negs = '-'+s + self.assertEqual(s, repr(float(s))) + self.assertEqual(negs, repr(float(negs))) + + + # Beginning with Python 2.6 float has cross platform compatible # ways to create and represent inf and nan class InfNanTest(unittest.TestCase): diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index c90f66d..054baf6 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -220,6 +220,11 @@ class FormatTest(unittest.TestCase): testformat("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable testformat("%a", "\u0374", "'\\u0374'") # printable + + # alternate float formatting + testformat('%g', 1.1, '1.1') + testformat('%#g', 1.1, '1.10000') + # Test exception for unknown format characters if verbose: print('Testing exceptions') diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 0d4d1b3..5d41e1b 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -113,6 +113,9 @@ class TypesTests(unittest.TestCase): self.assertEqual(1.5e-101.__format__('e'), '1.500000e-101') self.assertEqual('%e' % 1.5e-101, '1.500000e-101') + self.assertEqual('%g' % 1.0, '1') + self.assertEqual('%#g' % 1.0, '1.00000') + def test_normal_integers(self): # Ensure the first 256 integers are shared a = 256 @@ -358,6 +361,8 @@ class TypesTests(unittest.TestCase): self.assertRaises(TypeError, 3 .__format__, 0) # can't have ',' with 'n' self.assertRaises(ValueError, 3 .__format__, ",n") + # can't have ',' with 'c' + self.assertRaises(ValueError, 3 .__format__, ",c") # ensure that only int and float type specifiers work for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] + @@ -547,10 +552,34 @@ class TypesTests(unittest.TestCase): # a totaly empty format specifier means something else. # So, just use a sign flag test(1e200, '+g', '+1e+200') - test(1e200, '+', '+1.0e+200') + test(1e200, '+', '+1e+200') + test(1.1e200, '+g', '+1.1e+200') test(1.1e200, '+', '+1.1e+200') + # 0 padding + test(1234., '010f', '1234.000000') + test(1234., '011f', '1234.000000') + test(1234., '012f', '01234.000000') + test(-1234., '011f', '-1234.000000') + test(-1234., '012f', '-1234.000000') + test(-1234., '013f', '-01234.000000') + test(-1234.12341234, '013f', '-01234.123412') + test(-123456.12341234, '011.2f', '-0123456.12') + + # 0 padding with commas + test(1234., '011,f', '1,234.000000') + test(1234., '012,f', '1,234.000000') + test(1234., '013,f', '01,234.000000') + test(-1234., '012,f', '-1,234.000000') + test(-1234., '013,f', '-1,234.000000') + test(-1234., '014,f', '-01,234.000000') + test(-12345., '015,f', '-012,345.000000') + test(-123456., '016,f', '-0,123,456.000000') + test(-123456., '017,f', '-0,123,456.000000') + test(-123456.12341234, '017,f', '-0,123,456.123412') + test(-123456.12341234, '013,.2f', '-0,123,456.12') + # % formatting test(-1.0, '%', '-100.000000%') @@ -575,6 +604,24 @@ class TypesTests(unittest.TestCase): self.assertRaises(ValueError, format, 0.0, '#') self.assertRaises(ValueError, format, 0.0, '#20f') + def test_format_spec_errors(self): + # int, float, and string all share the same format spec + # mini-language parser. + + # Check that we can't ask for too many digits. This is + # probably a CPython specific test. It tries to put the width + # into a C long. + self.assertRaises(ValueError, format, 0, '1'*10000 + 'd') + + # Similar with the precision. + self.assertRaises(ValueError, format, 0, '.' + '1'*10000 + 'd') + + # And may as well test both. + self.assertRaises(ValueError, format, 0, '1'*1000 + '.' + '1'*10000 + 'd') + + # Make sure commas aren't allowed with various type codes + for code in 'xXobns': + self.assertRaises(ValueError, format, 0, ',' + code) def test_main(): run_unittest(TypesTests) |