[Python-checkins] r59459 - in python/trunk: Include/floatobject.h Lib/test/floating_points.txt Lib/test/test_float.py Makefile.pre.in Misc/NEWS Objects/doubledigits.c Objects/floatobject.c PCbuild/pythoncore.vcproj PCbuild8/pythoncore/pythoncore.vcproj PCbuild9/pythoncore.vcproj
christian.heimes
python-checkins at python.org
Mon Dec 10 23:28:56 CET 2007
Author: christian.heimes
Date: Mon Dec 10 23:28:56 2007
New Revision: 59459
Added:
python/trunk/Lib/test/floating_points.txt
- copied unchanged from r59458, python/branches/py3k/Lib/test/floating_points.txt
python/trunk/Objects/doubledigits.c
- copied unchanged from r59457, python/branches/py3k/Objects/doubledigits.c
Modified:
python/trunk/Include/floatobject.h
python/trunk/Lib/test/test_float.py
python/trunk/Makefile.pre.in
python/trunk/Misc/NEWS
python/trunk/Objects/floatobject.c
python/trunk/PCbuild/pythoncore.vcproj
python/trunk/PCbuild8/pythoncore/pythoncore.vcproj
python/trunk/PCbuild9/pythoncore.vcproj
Log:
Backport of r59456:59458 from py3k to trunk
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.
Modified: python/trunk/Include/floatobject.h
==============================================================================
--- python/trunk/Include/floatobject.h (original)
+++ python/trunk/Include/floatobject.h Mon Dec 10 23:28:56 2007
@@ -86,6 +86,10 @@
PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le);
PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le);
+/* Used to get the important decimal digits of a double */
+PyAPI_FUNC(int) _PyFloat_Digits(char *buf, double v, int *signum);
+PyAPI_FUNC(void) _PyFloat_DigitsInit(void);
+
/* The unpack routines read 4 or 8 bytes, starting at p. le is a bool
* argument, true if the string is in little-endian format (exponent
* last, at p+3 or p+7), false if big-endian (exponent first, at p).
Modified: python/trunk/Lib/test/test_float.py
==============================================================================
--- python/trunk/Lib/test/test_float.py (original)
+++ python/trunk/Lib/test/test_float.py Mon Dec 10 23:28:56 2007
@@ -1,5 +1,6 @@
import unittest, struct
+import os
from test import test_support
class FormatFunctionsTestCase(unittest.TestCase):
@@ -115,11 +116,25 @@
self.assertEquals(pos_neg(), neg_neg())
+class ReprTestCase(unittest.TestCase):
+ def test_repr(self):
+ floats_file = open(os.path.join(os.path.split(__file__)[0],
+ 'floating_points.txt'))
+ for line in floats_file:
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ v = eval(line)
+ self.assertEqual(v, eval(repr(v)))
+ floats_file.close()
+
+
def test_main():
test_support.run_unittest(
FormatFunctionsTestCase,
UnknownFormatTestCase,
- IEEEFormatTestCase)
+ IEEEFormatTestCase,
+ ReprTestCase)
if __name__ == '__main__':
test_main()
Modified: python/trunk/Makefile.pre.in
==============================================================================
--- python/trunk/Makefile.pre.in (original)
+++ python/trunk/Makefile.pre.in Mon Dec 10 23:28:56 2007
@@ -299,6 +299,7 @@
Objects/genobject.o \
Objects/fileobject.o \
Objects/floatobject.o \
+ Objects/doubledigits.o \
Objects/frameobject.o \
Objects/funcobject.o \
Objects/intobject.o \
Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS (original)
+++ python/trunk/Misc/NEWS Mon Dec 10 23:28:56 2007
@@ -12,6 +12,10 @@
Core and builtins
-----------------
+- 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'.
+
- Issue #1538: Avoid copying string in split/rsplit if the split
char is not found.
Modified: python/trunk/Objects/floatobject.c
==============================================================================
--- python/trunk/Objects/floatobject.c (original)
+++ python/trunk/Objects/floatobject.c Mon Dec 10 23:28:56 2007
@@ -306,6 +306,107 @@
format_float(buf, 100, 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; this replaces the functionality of the coercion
slot function. If conversion to double raises an exception, obj is
@@ -390,8 +491,8 @@
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 PyString_FromString(buf);
}
@@ -1290,6 +1391,9 @@
double_format = detected_double_format;
float_format = detected_float_format;
+
+ /* Initialize floating point repr */
+ _PyFloat_DigitsInit();
}
void
Modified: python/trunk/PCbuild/pythoncore.vcproj
==============================================================================
--- python/trunk/PCbuild/pythoncore.vcproj (original)
+++ python/trunk/PCbuild/pythoncore.vcproj Mon Dec 10 23:28:56 2007
@@ -485,6 +485,9 @@
RelativePath="..\Objects\dictobject.c">
</File>
<File
+ RelativePath="..\Objects\doubledigits.c">
+ </File>
+ <File
RelativePath="..\PC\dl_nt.c">
</File>
<File
Modified: python/trunk/PCbuild8/pythoncore/pythoncore.vcproj
==============================================================================
--- python/trunk/PCbuild8/pythoncore/pythoncore.vcproj (original)
+++ python/trunk/PCbuild8/pythoncore/pythoncore.vcproj Mon Dec 10 23:28:56 2007
@@ -820,6 +820,10 @@
>
</File>
<File
+ RelativePath="..\..\Objects\doubledigits.c"
+ >
+ </File>
+ <File
RelativePath="..\..\Objects\enumobject.c"
>
</File>
Modified: python/trunk/PCbuild9/pythoncore.vcproj
==============================================================================
--- python/trunk/PCbuild9/pythoncore.vcproj (original)
+++ python/trunk/PCbuild9/pythoncore.vcproj Mon Dec 10 23:28:56 2007
@@ -1371,6 +1371,10 @@
>
</File>
<File
+ RelativePath="..\Objects\doubledigits.c"
+ >
+ </File>
+ <File
RelativePath="..\Objects\enumobject.c"
>
</File>
More information about the Python-checkins
mailing list