Index: Python/pystrtod.c =================================================================== --- Python/pystrtod.c (revision 71669) +++ Python/pystrtod.c (working copy) @@ -384,6 +384,50 @@ } } +/* Remove trailing zeros after the decimal point from a numeric string; also + remove the decimal point if all digits following it are zero. The numeric + string must end in '\0', and should not have any leading or trailing + whitespace. Assumes that the decimal point is '.'. */ +Py_LOCAL_INLINE(void) +remove_trailing_zeros(char *buffer) +{ + char *old_fraction_end, *new_fraction_end, *end, *p; + + p = buffer; + if (*p == '-' || *p == '+') + /* Skip leading sign, if present */ + ++p; + while (ISDIGIT(Py_CHARMASK(*p))) + ++p; + + /* if there's no decimal point there's nothing to do */ + if (*p++ != '.') + return; + + /* scan any digits after the point */ + while (ISDIGIT(Py_CHARMASK(*p))) + ++p; + old_fraction_end = p; + + /* scan up to ending '\0' */ + while (*p != '\0') + p++; + /* +1 to make sure that we move the null byte as well */ + end = p+1; + + /* scan back from fraction_end, looking for removable zeros */ + p = old_fraction_end; + while (*(p-1) == '0') + --p; + /* and remove point if we've got that far */ + if (*(p-1) == '.') + --p; + new_fraction_end = p; + + memmove(new_fraction_end, old_fraction_end, end-old_fraction_end); +} + + /* see FORMATBUFLEN in unicodeobject.c */ #define FLOAT_FORMATBUFLEN 120 @@ -400,8 +444,8 @@ * a printf()-style format string. Allowed conversion * specifiers are 'e', 'E', 'f', 'F', 'g', 'G', and 'Z'. * - * 'Z' is the same as 'g', except it always has a decimal and - * at least one digit after the decimal. + * 'Z' is the same as 'g', except it always has a decimal point and + * at least one digit after the decimal point. * * Return value: The pointer to the buffer with the converted string. **/ @@ -498,6 +542,7 @@ char *p; int t; int upper = 0; + int strip_trailing_zeros = 0; /* Validate format_code, and map upper and lower case */ switch (format_code) { @@ -523,8 +568,16 @@ PyErr_BadInternalCall(); return NULL; } - precision = 17; - format_code = 'g'; + /* switch to exponential notation at 1e16 */ + if (fabs(val) >= 1e16) { + precision = 16; + format_code = 'e'; + strip_trailing_zeros = 1; + } + else { + precision = 17; + format_code = 'g'; + } break; case 's': /* str format */ /* Supplied precision is unused, must be 0. */ @@ -532,8 +585,17 @@ PyErr_BadInternalCall(); return NULL; } - precision = 12; - format_code = 'g'; + /* switch to exponential notation at 1e11, or 1e12 if we're + not adding a .0 */ + if (fabs(val) >= (flags & Py_DTSF_ADD_DOT_0 ? 1e11 : 1e12)) { + precision = 11; + format_code = 'e'; + strip_trailing_zeros = 1; + } + else { + precision = 12; + format_code = 'g'; + } break; default: PyErr_BadInternalCall(); @@ -552,13 +614,14 @@ t = Py_DTST_INFINITE; } else { t = Py_DTST_FINITE; - - - if (flags & Py_DTSF_ADD_DOT_0) + if ((flags & Py_DTSF_ADD_DOT_0) && (format_code != 'e')) format_code = 'Z'; PyOS_snprintf(format, 32, "%%%s.%i%c", (flags & Py_DTSF_ALT ? "#" : ""), precision, format_code); PyOS_ascii_formatd(buf, sizeof(buf), format, val); + /* remove trailing zeros if necessary */ + if (strip_trailing_zeros) + remove_trailing_zeros(buf); } len = strlen(buf);