Issue 5780: Fix test_float failures for legacy style float repr.

This commit is contained in:
Mark Dickinson 2009-04-17 22:40:53 +00:00
parent 7efad9ec5a
commit 3370cce4dd
2 changed files with 65 additions and 12 deletions

View File

@ -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,

View File

@ -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. */