summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorEric Smith <eric@trueblade.com>2009-04-16 20:16:10 (GMT)
committerEric Smith <eric@trueblade.com>2009-04-16 20:16:10 (GMT)
commit0923d1d8d7e428297461ed5145f06915c462b25b (patch)
treeb1fee964b1030c99285ae9d95e7e4dfb60dcded0 /Lib
parentb08a53a99def3fa949643974f713b5b189e21bc7 (diff)
downloadcpython-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.py76
-rw-r--r--Lib/test/test_format.py5
-rw-r--r--Lib/test/test_types.py49
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)