summaryrefslogtreecommitdiffstats
path: root/Objects/floatobject.c
diff options
context:
space:
mode:
authorEric Smith <eric@trueblade.com>2009-04-16 20:16:10 (GMT)
committerEric Smith <eric@trueblade.com>2009-04-16 20:16:10 (GMT)
commit0923d1d8d7e428297461ed5145f06915c462b25b (patch)
treeb1fee964b1030c99285ae9d95e7e4dfb60dcded0 /Objects/floatobject.c
parentb08a53a99def3fa949643974f713b5b189e21bc7 (diff)
downloadcpython-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.c145
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)
{