diff --git a/Doc/library/string.rst b/Doc/library/string.rst index d104931359d..959ea99a953 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -415,7 +415,8 @@ The available presentation types for floating point and decimal values are: | ``'f'`` | Fixed point. Displays the number as a fixed-point | | | number. | +---------+----------------------------------------------------------+ - | ``'F'`` | Fixed point. Same as ``'f'``. | + | ``'F'`` | Fixed point. Same as ``'f'``, but converts ``nan`` to | + | | ``NAN`` and ``inf`` to ``INF``. | +---------+----------------------------------------------------------+ | ``'g'`` | General format. This prints the number as a fixed-point | | | number, unless the number is too large, in which case | diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 1593f7bce4b..43282d684b0 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -507,6 +507,24 @@ class ComplexTest(unittest.TestCase): # make sure everything works in ''.format() self.assertEqual('*{0:.3f}*'.format(3.14159+2.71828j), '*3.142+2.718j*') + # issue 3382 + self.assertEqual(format(complex(NAN, NAN), 'f'), 'nan+nanj') + self.assertEqual(format(complex(1, NAN), 'f'), '1.000000+nanj') + self.assertEqual(format(complex(NAN, 1), 'f'), 'nan+1.000000j') + self.assertEqual(format(complex(NAN, -1), 'f'), 'nan-1.000000j') + self.assertEqual(format(complex(NAN, NAN), 'F'), 'NAN+NANj') + self.assertEqual(format(complex(1, NAN), 'F'), '1.000000+NANj') + self.assertEqual(format(complex(NAN, 1), 'F'), 'NAN+1.000000j') + self.assertEqual(format(complex(NAN, -1), 'F'), 'NAN-1.000000j') + self.assertEqual(format(complex(INF, INF), 'f'), 'inf+infj') + self.assertEqual(format(complex(1, INF), 'f'), '1.000000+infj') + self.assertEqual(format(complex(INF, 1), 'f'), 'inf+1.000000j') + self.assertEqual(format(complex(INF, -1), 'f'), 'inf-1.000000j') + self.assertEqual(format(complex(INF, INF), 'F'), 'INF+INFj') + self.assertEqual(format(complex(1, INF), 'F'), '1.000000+INFj') + self.assertEqual(format(complex(INF, 1), 'F'), 'INF+1.000000j') + self.assertEqual(format(complex(INF, -1), 'F'), 'INF-1.000000j') + def test_main(): support.run_unittest(ComplexTest) diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index b617fa37023..c259d4f3be7 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -320,6 +320,12 @@ class FormatTestCase(unittest.TestCase): self.assertRaises(ValueError, format, 1e-100, format_spec) self.assertRaises(ValueError, format, -1e-100, format_spec) + # issue 3382 + self.assertEqual(format(NAN, 'f'), 'nan') + self.assertEqual(format(NAN, 'F'), 'NAN') + self.assertEqual(format(INF, 'f'), 'inf') + self.assertEqual(format(INF, 'F'), 'INF') + @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), "test requires IEEE 754 doubles") def test_format_testfile(self): diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 21bb922c93c..3ede0572f6f 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -779,6 +779,14 @@ class UnicodeTest( return '\u1234' self.assertEqual('%s' % Wrapper(), '\u1234') + # issue 3382 + NAN = float('nan') + INF = float('inf') + self.assertEqual('%f' % NAN, 'nan') + self.assertEqual('%F' % NAN, 'NAN') + self.assertEqual('%f' % INF, 'inf') + self.assertEqual('%F' % INF, 'INF') + @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') def test_format_float(self): # should not format with a comma, but always with C locale diff --git a/Misc/NEWS b/Misc/NEWS index 35490d2d2d6..45bd9e758c7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ What's New in Python 3.1 beta 1? Core and Builtins ----------------- +- Issue #3382: float.__format__, complex.__format__, and %-formatting + no longer map 'F' to 'f'. Because of issue #5859 (below), this only + affects nan -> NAN and inf -> INF. + - Issue #5799: ntpath (ie, os.path on Windows) fully supports UNC pathnames in all operations, including splitdrive, split, etc. splitunc() now issues a PendingDeprecation warning. @@ -45,7 +49,7 @@ Core and Builtins restrictions for float formatting: '%.67f' % 12.34 and '%.120e' % 12.34 no longer raise an exception. -- Issue #1588: Add complex.__format__. For example, +- Issue #1588: Add complex.__format__. For example, format(complex(1, 2./3), '.5') now produces a sensible result. - Issue #5864: Fix empty format code formatting for floats so that it diff --git a/Objects/stringlib/formatter.h b/Objects/stringlib/formatter.h index 3b2218128dd..ea15c7bca8c 100644 --- a/Objects/stringlib/formatter.h +++ b/Objects/stringlib/formatter.h @@ -920,10 +920,6 @@ format_float_internal(PyObject *value, format the result. We take care of that later. */ type = 'g'; - /* 'F' is the same as 'f', per the PEP */ - if (type == 'F') - type = 'f'; - val = PyFloat_AsDouble(value); if (val == -1.0 && PyErr_Occurred()) goto done; @@ -939,8 +935,15 @@ format_float_internal(PyObject *value, #if PY_VERSION_HEX < 0x03010000 /* 3.1 no longer converts large 'f' to 'g'. */ - if ((type == 'f' || type == 'F') && fabs(val) >= 1e50) - type = 'g'; + if (fabs(val) >= 1e50) + switch (type) { + case 'f': + type = 'g'; + break; + case 'F': + type = 'G'; + break; + } #endif /* Cast "type", because if we're in unicode we need to pass a @@ -1114,10 +1117,6 @@ format_complex_internal(PyObject *value, format the result. We take care of that later. */ type = 'g'; - /* 'F' is the same as 'f', per the PEP */ - if (type == 'F') - type = 'f'; - if (precision < 0) precision = default_precision;