Issue #9337: Make float.__str__ identical to float.__repr__.

(And similarly for complex numbers.)
This commit is contained in:
Mark Dickinson 2010-08-04 20:56:28 +00:00
parent b6c5074920
commit 388122d43b
10 changed files with 63 additions and 85 deletions

View File

@ -92,18 +92,17 @@ thing in all languages that support your hardware's floating-point arithmetic
(although some languages may not *display* the difference by default, or in all
output modes).
Python's built-in :func:`str` function produces only 12 significant digits, and
you may wish to use that instead. It's unusual for ``eval(str(x))`` to
reproduce *x*, but the output may be more pleasant to look at::
For more pleasant output, you may may wish to use string formatting to produce a limited number of significant digits::
>>> str(math.pi)
>>> format(math.pi, '.12g') # give 12 significant digits
'3.14159265359'
>>> format(math.pi, '.2f') # give 2 digits after the point
'3.14'
>>> repr(math.pi)
'3.141592653589793'
>>> format(math.pi, '.2f')
'3.14'
It's important to realize that this is, in a real sense, an illusion: you're
simply rounding the *display* of the true machine value.

View File

@ -21,12 +21,6 @@ PyAPI_DATA(PyTypeObject) PyFloat_Type;
#define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type)
#define PyFloat_CheckExact(op) (Py_TYPE(op) == &PyFloat_Type)
/* The str() precision PyFloat_STR_PRECISION is chosen so that in most cases,
the rounding noise created by various operations is suppressed, while
giving plenty of precision for practical use. */
#define PyFloat_STR_PRECISION 12
#ifdef Py_NAN
#define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN)
#endif

View File

@ -314,43 +314,37 @@
%#.5g 234.56 -> 234.56
%#.6g 234.56 -> 234.560
-- for repr formatting see the separate test_short_repr test in
-- test_float.py. Not all platforms use short repr for floats.
-- str formatting. Result always includes decimal point and at
-- repr formatting. Result always includes decimal point and at
-- least one digit after the point, or an exponent.
%s 0 -> 0.0
%s 1 -> 1.0
%r 0 -> 0.0
%r 1 -> 1.0
%s 0.01 -> 0.01
%s 0.02 -> 0.02
%s 0.03 -> 0.03
%s 0.04 -> 0.04
%s 0.05 -> 0.05
%r 0.01 -> 0.01
%r 0.02 -> 0.02
%r 0.03 -> 0.03
%r 0.04 -> 0.04
%r 0.05 -> 0.05
-- str truncates to 12 significant digits
%s 1.234123412341 -> 1.23412341234
%s 1.23412341234 -> 1.23412341234
%s 1.2341234123 -> 1.2341234123
-- values >= 1e11 get an exponent
%s 10 -> 10.0
%s 100 -> 100.0
%s 1e10 -> 10000000000.0
%s 9.999e10 -> 99990000000.0
%s 99999999999 -> 99999999999.0
%s 99999999999.9 -> 99999999999.9
%s 99999999999.99 -> 1e+11
%s 1e11 -> 1e+11
%s 1e12 -> 1e+12
-- values >= 1e16 get an exponent
%r 10 -> 10.0
%r 100 -> 100.0
%r 1e15 -> 1000000000000000.0
%r 9.999e15 -> 9999000000000000.0
%r 9999999999999998 -> 9999999999999998.0
%r 9999999999999999 -> 1e+16
%r 1e16 -> 1e+16
%r 1e17 -> 1e+17
-- as do values < 1e-4
%s 1e-3 -> 0.001
%s 1.001e-4 -> 0.0001001
%s 1.000000000001e-4 -> 0.0001
%s 1.00000000001e-4 -> 0.000100000000001
%s 1.0000000001e-4 -> 0.00010000000001
%s 1e-4 -> 0.0001
%s 0.999999999999e-4 -> 9.99999999999e-05
%s 0.999e-4 -> 9.99e-05
%s 1e-5 -> 1e-05
%r 1e-3 -> 0.001
%r 1.001e-4 -> 0.0001001
%r 1.0000000000000001e-4 -> 0.0001
%r 1.000000000000001e-4 -> 0.0001000000000000001
%r 1.00000000001e-4 -> 0.000100000000001
%r 1.0000000001e-4 -> 0.00010000000001
%r 1e-4 -> 0.0001
%r 0.99999999999999999e-4 -> 0.0001
%r 0.9999999999999999e-4 -> 9.999999999999999e-05
%r 0.999999999999e-4 -> 9.99999999999e-05
%r 0.999e-4 -> 9.99e-05
%r 1e-5 -> 1e-05

View File

@ -617,7 +617,9 @@ 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)))
@requires_IEEE_754
class RoundTestCase(unittest.TestCase):

View File

@ -598,11 +598,11 @@ def decistmt(s):
The format of the exponent is inherited from the platform C library.
Known cases are "e-007" (Windows) and "e-07" (not Windows). Since
we're only showing 12 digits, and the 13th isn't close to 5, the
we're only showing 11 digits, and the 12th isn't close to 5, the
rest of the output should be platform-independent.
>>> exec(s) #doctest: +ELLIPSIS
-3.21716034272e-0...7
-3.2171603427...e-0...7
Output from calculations with Decimal should be identical across all
platforms.

View File

@ -80,8 +80,7 @@ class UnicodeDatabaseTest(unittest.TestCase):
class UnicodeFunctionsTest(UnicodeDatabaseTest):
# update this, if the database changes
expectedchecksum = '6ccf1b1a36460d2694f9b0b0f0324942fe70ede6'
expectedchecksum = 'e89a6380093a00a7685ac7b92e7367d737fcb79b'
def test_function_checksum(self):
data = []
h = hashlib.sha1()
@ -90,9 +89,9 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
char = chr(i)
data = [
# Properties
str(self.db.digit(char, -1)),
str(self.db.numeric(char, -1)),
str(self.db.decimal(char, -1)),
format(self.db.digit(char, -1), '.12g'),
format(self.db.numeric(char, -1), '.12g'),
format(self.db.decimal(char, -1), '.12g'),
self.db.category(char),
self.db.bidirectional(char),
self.db.decomposition(char),

View File

@ -12,6 +12,9 @@ What's New in Python 3.2 Alpha 2?
Core and Builtins
-----------------
- Issue #9337: The str() of a float or complex number is now identical
to its repr().
- Issue #9416: Fix some issues with complex formatting where the
output with no type specifier failed to match the str output:

View File

@ -394,12 +394,6 @@ complex_repr(PyComplexObject *v)
return complex_format(v, 0, 'r');
}
static PyObject *
complex_str(PyComplexObject *v)
{
return complex_format(v, PyFloat_STR_PRECISION, 'g');
}
static long
complex_hash(PyComplexObject *v)
{
@ -1104,7 +1098,7 @@ PyTypeObject PyComplex_Type = {
0, /* tp_as_mapping */
(hashfunc)complex_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)complex_str, /* tp_str */
(reprfunc)complex_repr, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */

View File

@ -305,11 +305,11 @@ convert_to_double(PyObject **v, double *dbl)
}
static PyObject *
float_str_or_repr(PyFloatObject *v, int precision, char format_code)
float_repr(PyFloatObject *v)
{
PyObject *result;
char *buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v),
format_code, precision,
'r', 0,
Py_DTSF_ADD_DOT_0,
NULL);
if (!buf)
@ -319,18 +319,6 @@ float_str_or_repr(PyFloatObject *v, int precision, char format_code)
return result;
}
static PyObject *
float_repr(PyFloatObject *v)
{
return float_str_or_repr(v, 0, 'r');
}
static PyObject *
float_str(PyFloatObject *v)
{
return float_str_or_repr(v, PyFloat_STR_PRECISION, 'g');
}
/* Comparison is pretty much a nightmare. When comparing float to float,
* we do it as straightforwardly (and long-windedly) as conceivable, so
* that, e.g., Python x == y delivers the same result as the platform
@ -1169,7 +1157,7 @@ float_hex(PyObject *v)
CONVERT_TO_DOUBLE(v, x);
if (Py_IS_NAN(x) || Py_IS_INFINITY(x))
return float_str((PyFloatObject *)v);
return float_repr((PyFloatObject *)v);
if (x == 0.0) {
if (copysign(1.0, x) == -1.0)
@ -1873,7 +1861,7 @@ PyTypeObject PyFloat_Type = {
0, /* tp_as_mapping */
(hashfunc)float_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)float_str, /* tp_str */
(reprfunc)float_repr, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */

View File

@ -950,11 +950,12 @@ format_float_internal(PyObject *value,
}
if (type == '\0') {
/* Omitted type specifier. This is like 'g' but with at least one
digit after the decimal point, and different default precision.*/
type = 'g';
default_precision = PyFloat_STR_PRECISION;
/* Omitted type specifier. Behaves in the same way as repr(x)
and str(x) if no precision is given, else like 'g', but with
at least one digit after the decimal point. */
flags |= Py_DTSF_ADD_DOT_0;
type = 'r';
default_precision = 0;
}
if (type == 'n')
@ -974,6 +975,8 @@ format_float_internal(PyObject *value,
if (precision < 0)
precision = default_precision;
else if (type == 'r')
type = 'g';
/* Cast "type", because if we're in unicode we need to pass a
8-bit char. This is safe, because we've restricted what "type"
@ -1134,8 +1137,8 @@ format_complex_internal(PyObject *value,
if (type == '\0') {
/* Omitted type specifier. Should be like str(self). */
type = 'g';
default_precision = PyFloat_STR_PRECISION;
type = 'r';
default_precision = 0;
if (re == 0.0 && copysign(1.0, re) == 1.0)
skip_re = 1;
else
@ -1149,6 +1152,8 @@ format_complex_internal(PyObject *value,
if (precision < 0)
precision = default_precision;
else if (type == 'r')
type = 'g';
/* Cast "type", because if we're in unicode we need to pass a
8-bit char. This is safe, because we've restricted what "type"