Kaydet (Commit) 827b35c9 authored tarafından Christian Heimes's avatar Christian Heimes

Issue #1580: New free format floating point representation based on…

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 b9f7f24c
......@@ -76,6 +76,10 @@ PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le);
*/
PyAPI_FUNC(int) _PyFloat_Repr(double x, char *p, size_t len);
/* 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).
......
import unittest, struct
import os
from test import test_support
class FormatFunctionsTestCase(unittest.TestCase):
......@@ -146,12 +147,26 @@ class FormatTestCase(unittest.TestCase):
self.assertRaises(ValueError, format, 3.0, "s")
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,
FormatTestCase)
FormatTestCase,
ReprTestCase)
if __name__ == '__main__':
test_main()
......@@ -301,6 +301,7 @@ OBJECT_OBJS= \
Objects/genobject.o \
Objects/fileobject.o \
Objects/floatobject.o \
Objects/doubledigits.o \
Objects/frameobject.o \
Objects/funcobject.o \
Objects/iterobject.o \
......
......@@ -12,6 +12,10 @@ What's New in Python 3.0a3?
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 #1573: Improper use of the keyword-only syntax makes the parser crash
- Issue #1564: The set implementation should special-case PyUnicode instead
......
This diff is collapsed.
......@@ -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
......
......@@ -488,6 +488,9 @@
RelativePath="..\Objects\dictobject.c">
</File>
<File
RelativePath="..\Objects\doubledigits.c">
</File>
<File
RelativePath="..\PC\dl_nt.c">
</File>
<File
......
......@@ -827,6 +827,10 @@
RelativePath="..\..\Objects\dictobject.c"
>
</File>
<File
RelativePath="..\..\Objects\doubledigits.c"
>
</File>
<File
RelativePath="..\..\Objects\memoryobject.c"
>
......
......@@ -1362,6 +1362,10 @@
RelativePath="..\Objects\dictobject.c"
>
</File>
<File
RelativePath="..\Objects\doubledigits.c"
>
</File>
<File
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