summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Misc/NEWS12
-rw-r--r--Python/pystrtod.c65
2 files changed, 65 insertions, 12 deletions
diff --git a/Misc/NEWS b/Misc/NEWS
index d4774dd..f0ed225 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -20,14 +20,7 @@ Core and Builtins
- Implement PEP 378, Format Specifier for Thousands Separator, for
floats.
-- The repr function switches to exponential notation at 1e16, not 1e17
- as it did before. This change applies to both 'short' and legacy
- float repr styles. For the new repr style, it avoids misleading
- output in some cases: an example is repr(2e16+8), which gives
- '2.000000000000001e+16'; without this change it would have produced
- '20000000000000010.0' instead.
-
-- Similarly, the str function switches to exponential notation at
+- The str function switches to exponential notation at
1e11, not 1e12. This avoids printing 13 significant digits in
situations where only 12 of them are correct. Example problem
value: str(1e11 + 0.5). (This minor issue has existed in 2.x for a
@@ -44,6 +37,9 @@ Core and Builtins
finite float x, repr(x) now outputs a string based on the shortest
sequence of decimal digits that rounds to x. Previous behaviour was
to output 17 significant digits and then strip trailing zeros.
+ Another minor difference is that the new repr switches to
+ exponential notation at 1e16 instead of the previous 1e17; this
+ avoids misleading output in some cases.
There's a new sys attribute sys.float_repr_style, which takes
the value 'short' to indicate that we're using short float repr,
diff --git a/Python/pystrtod.c b/Python/pystrtod.c
index 9e00823..95fbd89 100644
--- a/Python/pystrtod.c
+++ b/Python/pystrtod.c
@@ -485,6 +485,50 @@ PyOS_ascii_formatd(char *buffer,
/* The fallback code to use if _Py_dg_dtoa is not available. */
+/* 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);
+}
+
+
PyAPI_FUNC(char *) PyOS_double_to_string(double val,
char format_code,
int precision,
@@ -498,6 +542,7 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
char *p;
int t;
int upper = 0;
+ int strip_trailing_zeros = 0;
/* Validate format_code, and map upper and lower case */
switch (format_code) {
@@ -532,8 +577,17 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
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();
@@ -554,11 +608,14 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
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);
@@ -671,7 +728,7 @@ format_float_short(double d, char format_code,
assert(digits_end != NULL && digits_end >= digits);
digits_len = digits_end - digits;
- if (digits_len && !isdigit(digits[0])) {
+ if (digits_len && !isdigit(Py_CHARMASK(digits[0]))) {
/* Infinities and nans here; adapt Gay's output,
so convert Infinity to inf and NaN to nan, and
ignore sign of nan. Then return. */