diff options
author | Christian Heimes <christian@cheimes.de> | 2007-12-10 22:19:17 (GMT) |
---|---|---|
committer | Christian Heimes <christian@cheimes.de> | 2007-12-10 22:19:17 (GMT) |
commit | 827b35c9fed9e842c96b41198b26cee96a3e679b (patch) | |
tree | 14eb9fb523b002aab63bc4b99fbbd1bae16f56c2 /Objects/floatobject.c | |
parent | b9f7f24c2537e40e06de6f12c29f786215b64912 (diff) | |
download | cpython-827b35c9fed9e842c96b41198b26cee96a3e679b.zip cpython-827b35c9fed9e842c96b41198b26cee96a3e679b.tar.gz cpython-827b35c9fed9e842c96b41198b26cee96a3e679b.tar.bz2 |
Issue #1580: New free format floating point representation based on "Floating-Point Printer Sample Code", by Robert G. Burger. For example repr(11./5) now returns '2.2' instead of '2.2000000000000002'.
Thanks to noam for the patch! I had to modify doubledigits.c slightly to support X64 and IA64 machines on Windows. I also added the new file to the three project files.
Diffstat (limited to 'Objects/floatobject.c')
-rw-r--r-- | Objects/floatobject.c | 108 |
1 files changed, 106 insertions, 2 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c index d346ef6..b17f7be 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -281,6 +281,107 @@ format_float(char *buf, size_t buflen, PyFloatObject *v, int precision) format_double(buf, buflen, PyFloat_AS_DOUBLE(v), precision); } +/* The following function is based on Tcl_PrintDouble, + * from tclUtil.c. + */ + +#define is_infinite(d) ( (d) > DBL_MAX || (d) < -DBL_MAX ) +#define is_nan(d) ((d) != (d)) + +static void +format_double_repr(char *dst, double value) +{ + char *p, c; + int exp; + int signum; + char buffer[30]; + + /* + * Handle NaN. + */ + + if (is_nan(value)) { + strcpy(dst, "nan"); + return; + } + + /* + * Handle infinities. + */ + + if (is_infinite(value)) { + if (value < 0) { + strcpy(dst, "-inf"); + } else { + strcpy(dst, "inf"); + } + return; + } + + /* + * Ordinary (normal and denormal) values. + */ + + exp = _PyFloat_Digits(buffer, value, &signum)+1; + if (signum) { + *dst++ = '-'; + } + p = buffer; + if (exp < -3 || exp > 17) { + /* + * E format for numbers < 1e-3 or >= 1e17. + */ + + *dst++ = *p++; + c = *p; + if (c != '\0') { + *dst++ = '.'; + while (c != '\0') { + *dst++ = c; + c = *++p; + } + } + sprintf(dst, "e%+d", exp-1); + } else { + /* + * F format for others. + */ + + if (exp <= 0) { + *dst++ = '0'; + } + c = *p; + while (exp-- > 0) { + if (c != '\0') { + *dst++ = c; + c = *++p; + } else { + *dst++ = '0'; + } + } + *dst++ = '.'; + if (c == '\0') { + *dst++ = '0'; + } else { + while (++exp < 0) { + *dst++ = '0'; + } + while (c != '\0') { + *dst++ = c; + c = *++p; + } + } + *dst++ = '\0'; + } +} + +static void +format_float_repr(char *buf, PyFloatObject *v) +{ + assert(PyFloat_Check(v)); + format_double_repr(buf, PyFloat_AS_DOUBLE(v)); +} + /* 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 @@ -333,8 +434,8 @@ convert_to_double(PyObject **v, double *dbl) static PyObject * float_repr(PyFloatObject *v) { - char buf[100]; - format_float(buf, sizeof(buf), v, PREC_REPR); + char buf[30]; + format_float_repr(buf, v); return PyUnicode_FromString(buf); } @@ -1226,6 +1327,9 @@ _PyFloat_Init(void) double_format = detected_double_format; float_format = detected_float_format; + + /* Initialize floating point repr */ + _PyFloat_DigitsInit(); } void |