summaryrefslogtreecommitdiffstats
path: root/Objects/floatobject.c
diff options
context:
space:
mode:
authorChristian Heimes <christian@cheimes.de>2007-12-10 22:19:17 (GMT)
committerChristian Heimes <christian@cheimes.de>2007-12-10 22:19:17 (GMT)
commit827b35c9fed9e842c96b41198b26cee96a3e679b (patch)
tree14eb9fb523b002aab63bc4b99fbbd1bae16f56c2 /Objects/floatobject.c
parentb9f7f24c2537e40e06de6f12c29f786215b64912 (diff)
downloadcpython-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.c108
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