mirror of https://github.com/python/cpython.git
Issue 5780: Fix test_float failures for legacy style float repr.
This commit is contained in:
parent
7efad9ec5a
commit
3370cce4dd
12
Misc/NEWS
12
Misc/NEWS
|
@ -20,14 +20,7 @@ Core and Builtins
|
||||||
- Implement PEP 378, Format Specifier for Thousands Separator, for
|
- Implement PEP 378, Format Specifier for Thousands Separator, for
|
||||||
floats.
|
floats.
|
||||||
|
|
||||||
- The repr function switches to exponential notation at 1e16, not 1e17
|
- The str function switches to exponential notation at
|
||||||
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
|
|
||||||
1e11, not 1e12. This avoids printing 13 significant digits in
|
1e11, not 1e12. This avoids printing 13 significant digits in
|
||||||
situations where only 12 of them are correct. Example problem
|
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
|
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
|
finite float x, repr(x) now outputs a string based on the shortest
|
||||||
sequence of decimal digits that rounds to x. Previous behaviour was
|
sequence of decimal digits that rounds to x. Previous behaviour was
|
||||||
to output 17 significant digits and then strip trailing zeros.
|
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
|
There's a new sys attribute sys.float_repr_style, which takes
|
||||||
the value 'short' to indicate that we're using short float repr,
|
the value 'short' to indicate that we're using short float repr,
|
||||||
|
|
|
@ -485,6 +485,50 @@ PyOS_ascii_formatd(char *buffer,
|
||||||
|
|
||||||
/* The fallback code to use if _Py_dg_dtoa is not available. */
|
/* 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,
|
PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
char format_code,
|
char format_code,
|
||||||
int precision,
|
int precision,
|
||||||
|
@ -498,6 +542,7 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
char *p;
|
char *p;
|
||||||
int t;
|
int t;
|
||||||
int upper = 0;
|
int upper = 0;
|
||||||
|
int strip_trailing_zeros = 0;
|
||||||
|
|
||||||
/* Validate format_code, and map upper and lower case */
|
/* Validate format_code, and map upper and lower case */
|
||||||
switch (format_code) {
|
switch (format_code) {
|
||||||
|
@ -532,8 +577,17 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
precision = 12;
|
/* switch to exponential notation at 1e11, or 1e12 if we're
|
||||||
format_code = 'g';
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
|
@ -554,11 +608,14 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
t = Py_DTST_FINITE;
|
t = Py_DTST_FINITE;
|
||||||
|
|
||||||
|
|
||||||
if (flags & Py_DTSF_ADD_DOT_0)
|
if ((flags & Py_DTSF_ADD_DOT_0) && (format_code != 'e'))
|
||||||
format_code = 'Z';
|
format_code = 'Z';
|
||||||
|
|
||||||
PyOS_snprintf(format, 32, "%%%s.%i%c", (flags & Py_DTSF_ALT ? "#" : ""), precision, format_code);
|
PyOS_snprintf(format, 32, "%%%s.%i%c", (flags & Py_DTSF_ALT ? "#" : ""), precision, format_code);
|
||||||
PyOS_ascii_formatd(buf, sizeof(buf), format, val);
|
PyOS_ascii_formatd(buf, sizeof(buf), format, val);
|
||||||
|
/* remove trailing zeros if necessary */
|
||||||
|
if (strip_trailing_zeros)
|
||||||
|
remove_trailing_zeros(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen(buf);
|
len = strlen(buf);
|
||||||
|
@ -671,7 +728,7 @@ format_float_short(double d, char format_code,
|
||||||
assert(digits_end != NULL && digits_end >= digits);
|
assert(digits_end != NULL && digits_end >= digits);
|
||||||
digits_len = 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,
|
/* Infinities and nans here; adapt Gay's output,
|
||||||
so convert Infinity to inf and NaN to nan, and
|
so convert Infinity to inf and NaN to nan, and
|
||||||
ignore sign of nan. Then return. */
|
ignore sign of nan. Then return. */
|
||||||
|
|
Loading…
Reference in New Issue