Kaydet (Commit) 284d9276 authored tarafından Christian Heimes's avatar Christian Heimes

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.
üst 8c3d0f78
...@@ -86,6 +86,10 @@ PyAPI_FUNC(void) PyFloat_AsString(char*, PyFloatObject *v); ...@@ -86,6 +86,10 @@ PyAPI_FUNC(void) PyFloat_AsString(char*, PyFloatObject *v);
PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le);
PyAPI_FUNC(int) _PyFloat_Pack8(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 /* 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 * 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). * last, at p+3 or p+7), false if big-endian (exponent first, at p).
......
This diff is collapsed.
import unittest, struct import unittest, struct
import os
from test import test_support from test import test_support
class FormatFunctionsTestCase(unittest.TestCase): class FormatFunctionsTestCase(unittest.TestCase):
...@@ -115,11 +116,25 @@ class IEEEFormatTestCase(unittest.TestCase): ...@@ -115,11 +116,25 @@ class IEEEFormatTestCase(unittest.TestCase):
self.assertEquals(pos_neg(), neg_neg()) 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(): def test_main():
test_support.run_unittest( test_support.run_unittest(
FormatFunctionsTestCase, FormatFunctionsTestCase,
UnknownFormatTestCase, UnknownFormatTestCase,
IEEEFormatTestCase) IEEEFormatTestCase,
ReprTestCase)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
...@@ -299,6 +299,7 @@ OBJECT_OBJS= \ ...@@ -299,6 +299,7 @@ OBJECT_OBJS= \
Objects/genobject.o \ Objects/genobject.o \
Objects/fileobject.o \ Objects/fileobject.o \
Objects/floatobject.o \ Objects/floatobject.o \
Objects/doubledigits.o \
Objects/frameobject.o \ Objects/frameobject.o \
Objects/funcobject.o \ Objects/funcobject.o \
Objects/intobject.o \ Objects/intobject.o \
......
...@@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1? ...@@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
Core and builtins 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 - Issue #1538: Avoid copying string in split/rsplit if the split
char is not found. char is not found.
......
This diff is collapsed.
...@@ -306,6 +306,107 @@ PyFloat_AsStringEx(char *buf, PyFloatObject *v, int precision) ...@@ -306,6 +306,107 @@ PyFloat_AsStringEx(char *buf, PyFloatObject *v, int precision)
format_float(buf, 100, v, precision); 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 /* Macro and helper that convert PyObject obj to a C double and store
the value in dbl; this replaces the functionality of the coercion the value in dbl; this replaces the functionality of the coercion
slot function. If conversion to double raises an exception, obj is slot function. If conversion to double raises an exception, obj is
...@@ -390,8 +491,8 @@ float_print(PyFloatObject *v, FILE *fp, int flags) ...@@ -390,8 +491,8 @@ float_print(PyFloatObject *v, FILE *fp, int flags)
static PyObject * static PyObject *
float_repr(PyFloatObject *v) float_repr(PyFloatObject *v)
{ {
char buf[100]; char buf[30];
format_float(buf, sizeof(buf), v, PREC_REPR); format_float_repr(buf, v);
return PyString_FromString(buf); return PyString_FromString(buf);
} }
...@@ -1290,6 +1391,9 @@ _PyFloat_Init(void) ...@@ -1290,6 +1391,9 @@ _PyFloat_Init(void)
double_format = detected_double_format; double_format = detected_double_format;
float_format = detected_float_format; float_format = detected_float_format;
/* Initialize floating point repr */
_PyFloat_DigitsInit();
} }
void void
......
...@@ -485,6 +485,9 @@ ...@@ -485,6 +485,9 @@
RelativePath="..\Objects\dictobject.c"> RelativePath="..\Objects\dictobject.c">
</File> </File>
<File <File
RelativePath="..\Objects\doubledigits.c">
</File>
<File
RelativePath="..\PC\dl_nt.c"> RelativePath="..\PC\dl_nt.c">
</File> </File>
<File <File
......
...@@ -819,6 +819,10 @@ ...@@ -819,6 +819,10 @@
RelativePath="..\..\Objects\dictobject.c" RelativePath="..\..\Objects\dictobject.c"
> >
</File> </File>
<File
RelativePath="..\..\Objects\doubledigits.c"
>
</File>
<File <File
RelativePath="..\..\Objects\enumobject.c" RelativePath="..\..\Objects\enumobject.c"
> >
......
...@@ -1370,6 +1370,10 @@ ...@@ -1370,6 +1370,10 @@
RelativePath="..\Objects\dictobject.c" RelativePath="..\Objects\dictobject.c"
> >
</File> </File>
<File
RelativePath="..\Objects\doubledigits.c"
>
</File>
<File <File
RelativePath="..\Objects\enumobject.c" RelativePath="..\Objects\enumobject.c"
> >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment