diff options
author | Eric Smith <eric@trueblade.com> | 2009-04-16 20:16:10 (GMT) |
---|---|---|
committer | Eric Smith <eric@trueblade.com> | 2009-04-16 20:16:10 (GMT) |
commit | 0923d1d8d7e428297461ed5145f06915c462b25b (patch) | |
tree | b1fee964b1030c99285ae9d95e7e4dfb60dcded0 /Objects/floatobject.c | |
parent | b08a53a99def3fa949643974f713b5b189e21bc7 (diff) | |
download | cpython-0923d1d8d7e428297461ed5145f06915c462b25b.zip cpython-0923d1d8d7e428297461ed5145f06915c462b25b.tar.gz cpython-0923d1d8d7e428297461ed5145f06915c462b25b.tar.bz2 |
The other half of Issue #1580: use short float repr where possible.
Addresses the float -> string conversion, using David Gay's code which
was added in Mark Dickinson's checkin r71663.
Also addresses these, which are intertwined with the short repr
changes:
- Issue #5772: format(1e100, '<') produces '1e+100', not '1.0e+100'
- Issue #5515: 'n' formatting with commas no longer works poorly
with leading zeros.
- PEP 378 Format Specifier for Thousands Separator: implemented
for floats.
Diffstat (limited to 'Objects/floatobject.c')
-rw-r--r-- | Objects/floatobject.c | 145 |
1 files changed, 31 insertions, 114 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 2ef4d1a..2fbe810 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -197,8 +197,7 @@ PyFloat_FromString(PyObject *v) sp = s; /* We don't care about overflow or underflow. If the platform supports * them, infinities and signed zeroes (on underflow) are fine. - * However, strtod can return 0 for denormalized numbers, where atof - * does not. So (alas!) we special-case a zero result. Note that + * However, strtod can return 0 for denormalized numbers. Note that * whether strtod sets errno on underflow is not defined, so we can't * key off errno. */ @@ -259,14 +258,6 @@ PyFloat_FromString(PyObject *v) "null byte in argument for float()"); goto error; } - if (x == 0.0) { - /* See above -- may have been strtod being anal - about denorms. */ - PyFPE_START_PROTECT("atof", goto error) - x = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(x) - errno = 0; /* whether atof ever set errno is undefined */ - } result = PyFloat_FromDouble(x); error: if (s_buffer) @@ -320,72 +311,6 @@ PyFloat_AsDouble(PyObject *op) return val; } -/* Methods */ - -static void -format_double(char *buf, size_t buflen, double ob_fval, int precision) -{ - register char *cp; - char format[32]; - int i; - - /* Subroutine for float_repr, float_str and float_print. - We want float numbers to be recognizable as such, - i.e., they should contain a decimal point or an exponent. - However, %g may print the number as an integer; - in such cases, we append ".0" to the string. */ - - PyOS_snprintf(format, 32, "%%.%ig", precision); - PyOS_ascii_formatd(buf, buflen, format, ob_fval); - cp = buf; - if (*cp == '-') - cp++; - for (; *cp != '\0'; cp++) { - /* Any non-digit means it's not an integer; - this takes care of NAN and INF as well. */ - if (!isdigit(Py_CHARMASK(*cp))) - break; - } - if (*cp == '\0') { - *cp++ = '.'; - *cp++ = '0'; - *cp++ = '\0'; - return; - } - /* Checking the next three chars should be more than enough to - * detect inf or nan, even on Windows. We check for inf or nan - * at last because they are rare cases. - */ - for (i=0; *cp != '\0' && i<3; cp++, i++) { - if (isdigit(Py_CHARMASK(*cp)) || *cp == '.') - continue; - /* found something that is neither a digit nor point - * it might be a NaN or INF - */ -#ifdef Py_NAN - if (Py_IS_NAN(ob_fval)) { - strcpy(buf, "nan"); - } - else -#endif - if (Py_IS_INFINITY(ob_fval)) { - cp = buf; - if (*cp == '-') - cp++; - strcpy(cp, "inf"); - } - break; - } - -} - -static void -format_float(char *buf, size_t buflen, PyFloatObject *v, int precision) -{ - assert(PyFloat_Check(v)); - format_double(buf, buflen, PyFloat_AS_DOUBLE(v), precision); -} - /* Macro and helper that convert PyObject obj to a C double and store the value in dbl. If conversion to double raises an exception, obj is set to NULL, and the function invoking this macro returns NULL. If @@ -398,6 +323,8 @@ format_float(char *buf, size_t buflen, PyFloatObject *v, int precision) else if (convert_to_double(&(obj), &(dbl)) < 0) \ return obj; +/* Methods */ + static int convert_to_double(PyObject **v, double *dbl) { @@ -418,38 +345,30 @@ convert_to_double(PyObject **v, double *dbl) return 0; } -/* Precisions used by repr() and str(), respectively. - - The repr() precision (17 significant decimal digits) is the minimal number - that is guaranteed to have enough precision so that if the number is read - back in the exact same binary value is recreated. This is true for IEEE - floating point by design, and also happens to work for all other modern - hardware. - - The str() precision is chosen so that in most cases, the rounding noise - created by various operations is suppressed, while giving plenty of - precision for practical use. - -*/ - -#define PREC_REPR 17 -#define PREC_STR 12 +static PyObject * +float_str_or_repr(PyFloatObject *v, char format_code) +{ + PyObject *result; + char *buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v), + format_code, 0, Py_DTSF_ADD_DOT_0, + NULL); + if (!buf) + return PyErr_NoMemory(); + result = PyUnicode_FromString(buf); + PyMem_Free(buf); + return result; +} static PyObject * float_repr(PyFloatObject *v) { - char buf[100]; - format_float(buf, sizeof(buf), v, PREC_REPR); - - return PyUnicode_FromString(buf); + return float_str_or_repr(v, 'r'); } static PyObject * float_str(PyFloatObject *v) { - char buf[100]; - format_float(buf, sizeof(buf), v, PREC_STR); - return PyUnicode_FromString(buf); + return float_str_or_repr(v, 's'); } /* Comparison is pretty much a nightmare. When comparing float to float, @@ -1980,15 +1899,21 @@ PyFloat_Fini(void) i++, p++) { if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) { - char buf[100]; - format_float(buf, sizeof(buf), p, PREC_STR); - /* XXX(twouters) cast refcount to - long until %zd is universally - available - */ - fprintf(stderr, + char *buf = PyOS_double_to_string( + PyFloat_AS_DOUBLE(p), 'r', + 0, 0, NULL); + if (buf) { + /* XXX(twouters) cast + refcount to long + until %zd is + universally + available + */ + fprintf(stderr, "# <float at %p, refcnt=%ld, val=%s>\n", p, (long)Py_REFCNT(p), buf); + PyMem_Free(buf); + } } } list = list->next; @@ -2233,14 +2158,6 @@ _PyFloat_Pack8(double x, unsigned char *p, int le) } } -/* Should only be used by marshal. */ -int -_PyFloat_Repr(double x, char *p, size_t len) -{ - format_double(p, len, x, PREC_REPR); - return (int)strlen(p); -} - double _PyFloat_Unpack4(const unsigned char *p, int le) { |