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
|
||||
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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue