Index: Objects/floatobject.c =================================================================== --- Objects/floatobject.c (revision 64697) +++ Objects/floatobject.c (working copy) @@ -20,6 +20,22 @@ extern int finite(double); #endif +/* Precisions used by repr() and str(), respectively. + + The repr() precision (17 significant decimal digits) is the minimal number + that is guaranteed to have enough precision so that if the number is read + back in the exact same binary value is recreated. This is true for IEEE + floating point by design, and also happens to work for all other modern + hardware. + + The 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 PREC_REPR 17 +#define PREC_STR 12 + /* Special free list -- see comments for same code in intobject.c. */ #define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ #define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ @@ -313,31 +329,77 @@ { register char *cp; char format[32]; + int ndigits; int i; - /* Subroutine for float_repr, float_str and float_print. + /* Subroutine for float_repr and float_str. We want float numbers to be recognizable as such, i.e., they should contain a decimal point or an exponent. However, %g may print the number as an integer; - in such cases, we append ".0" to the string. */ + in such cases, we append ".0" to the string. + In addition, if exactly PREC_REPR digits are seen, + we try with PREC_STR precision, to see if that produces + a value that evaluates to the input; if so we use that. + This avoids naive user complaints about 1.1 rendering + as 1.1000000000000001. If they start complaining about + 1.234567890123 rendering as 1.2345678901229999, well, + we'll ask them to rewrite this code, with a reference to + http://bugs.python.org/issue1580. + + We also normalize infinities and NaNs here. */ + PyOS_snprintf(format, 32, "%%.%ig", precision); PyOS_ascii_formatd(buf, buflen, format, ob_fval); + again: cp = buf; if (*cp == '-') cp++; + ndigits = 0; for (; *cp != '\0'; cp++) { /* Any non-digit means it's not an integer; this takes care of NAN and INF as well. */ if (!isdigit(Py_CHARMASK(*cp))) break; + ++ndigits; } - if (*cp == '\0') { + if (*cp == '.') { + cp++; + for (; *cp != '\0'; cp++) { + /* Count digits after '.' */ + if (!isdigit(Py_CHARMASK(*cp))) + break; + ++ndigits; + } + } + else if (*cp == '\0') { *cp++ = '.'; *cp++ = '0'; *cp++ = '\0'; + } + if (ndigits == PREC_REPR && precision == PREC_REPR) { + /* Try again with less precision. */ + char altbuf[100]; + double x; + char *end; + precision = PREC_STR; /* Make sure we won't get here again */ + PyOS_snprintf(format, 32, "%%.%ig", precision); + PyOS_snprintf(altbuf, sizeof(altbuf), format, ob_fval); + PyFPE_START_PROTECT("strtod", goto error) + x = PyOS_ascii_strtod(altbuf, (char **)&end); + PyFPE_END_PROTECT(x) + if (x == ob_fval) { + strncpy(buf, altbuf, buflen); + buf[buflen-1] = '\0'; + goto again; + } +#ifdef WANT_SIGFPE_HANDLER + error: ; +#endif + } + if (*cp == '\0') return; - } + /* Checking the next three chars should be more than enough to * detect inf or nan, even on Windows. We check for inf or nan * at last because they are rare cases. @@ -404,23 +466,6 @@ return 0; } -/* Precisions used by repr() and str(), respectively. - - The repr() precision (17 significant decimal digits) is the minimal number - that is guaranteed to have enough precision so that if the number is read - back in the exact same binary value is recreated. This is true for IEEE - floating point by design, and also happens to work for all other modern - hardware. - - The 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 PREC_REPR 17 -#define PREC_STR 12 - static PyObject * float_repr(PyFloatObject *v) {