Commit 388122d4 authored by Mark Dickinson's avatar Mark Dickinson

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

(And similarly for complex numbers.)
parent b6c50749
......@@ -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.
......
......@@ -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
......
......@@ -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
%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 -> 0.0
%r 1 -> 1.0
-- str truncates to 12 significant digits
%s 1.234123412341 -> 1.23412341234
%s 1.23412341234 -> 1.23412341234
%s 1.2341234123 -> 1.2341234123
%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
-- 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
......@@ -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):
......
......@@ -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.
......
......@@ -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),
......
......@@ -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:
......
......@@ -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 */
......
......@@ -305,32 +305,20 @@ 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)
return PyErr_NoMemory();
return PyErr_NoMemory();
result = PyUnicode_FromString(buf);
PyMem_Free(buf);
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 */
......
......@@ -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"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment