Remove restriction on precision when formatting floats. This is the

first step towards removing the %f -> %g switch (see issues 7117,
5859).
This commit is contained in:
Mark Dickinson 2009-11-23 18:46:41 +00:00
parent 5c456e6f45
commit 18cfada1ea
4 changed files with 47 additions and 122 deletions

View File

@ -1090,13 +1090,6 @@ class MixinStrUnicodeUserStringTest:
value = 0.01 value = 0.01
for x in xrange(60): for x in xrange(60):
value = value * 3.141592655 / 3.0 * 10.0 value = value * 3.141592655 / 3.0 * 10.0
# The formatfloat() code in stringobject.c and
# unicodeobject.c uses a 120 byte buffer and switches from
# 'f' formatting to 'g' at precision 50, so we expect
# OverflowErrors for the ranges x < 50 and prec >= 67.
if x < 50 and prec >= 67:
self.checkraises(OverflowError, format, "__mod__", value)
else:
self.checkcall(format, "__mod__", value) self.checkcall(format, "__mod__", value)
def test_inplace_rewrites(self): def test_inplace_rewrites(self):

View File

@ -12,6 +12,10 @@ What's New in Python 2.7 alpha 1
Core and Builtins Core and Builtins
----------------- -----------------
- Remove restrictions on precision when formatting floats. E.g.,
"%.120g" % 1e-100 used to raise OverflowError, but now gives the
requested 120 significant digits instead.
- Add Py3k warnings for parameter names in parenthesis. - Add Py3k warnings for parameter names in parenthesis.
- Issue #7362: Give a proper error message for def f((x)=3): pass. - Issue #7362: Give a proper error message for def f((x)=3): pass.

View File

@ -4379,72 +4379,36 @@ getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx)
#define F_ALT (1<<3) #define F_ALT (1<<3)
#define F_ZERO (1<<4) #define F_ZERO (1<<4)
Py_LOCAL_INLINE(int) /* Returns a new reference to a PyString object, or NULL on failure. */
formatfloat(char *buf, size_t buflen, int flags,
int prec, int type, PyObject *v) static PyObject *
formatfloat(PyObject *v, int flags, int prec, int type)
{ {
char *tmp; char *p;
PyObject *result;
double x; double x;
Py_ssize_t len;
x = PyFloat_AsDouble(v); x = PyFloat_AsDouble(v);
if (x == -1.0 && PyErr_Occurred()) { if (x == -1.0 && PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError, "float argument required, " PyErr_Format(PyExc_TypeError, "float argument required, "
"not %.200s", Py_TYPE(v)->tp_name); "not %.200s", Py_TYPE(v)->tp_name);
return -1; return NULL;
} }
if (prec < 0) if (prec < 0)
prec = 6; prec = 6;
#if SIZEOF_INT > 4
/* make sure that the decimal representation of precision really does
need at most 10 digits: platforms with sizeof(int) == 8 exist! */
if (prec > 0x7fffffff) {
PyErr_SetString(PyExc_OverflowError,
"outrageously large precision "
"for formatted float");
return -1;
}
#endif
if (type == 'f' && fabs(x) >= 1e50) if (type == 'f' && fabs(x) >= 1e50)
type = 'g'; type = 'g';
/* Worst case length calc to ensure no buffer overrun:
'g' formats: p = PyOS_double_to_string(x, type, prec,
fmt = %#.<prec>g (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL);
buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
for any double rep.)
len = 1 + prec + 1 + 2 + 5 = 9 + prec
'f' formats: if (p == NULL)
buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) return NULL;
len = 1 + 50 + 1 + prec = 52 + prec result = PyString_FromStringAndSize(p, strlen(p));
PyMem_Free(p);
If prec=0 the effective precision is 1 (the leading digit is return result;
always given), therefore increase the length by one.
*/
if (((type == 'g' || type == 'G') &&
buflen <= (size_t)10 + (size_t)prec) ||
(type == 'f' && buflen <= (size_t)53 + (size_t)prec)) {
PyErr_SetString(PyExc_OverflowError,
"formatted float is too long (precision too large?)");
return -1;
}
tmp = PyOS_double_to_string(x, type, prec,
(flags&F_ALT)?Py_DTSF_ALT:0, NULL);
if (!tmp)
return -1;
len = strlen(tmp);
if (len >= buflen) {
PyErr_SetString(PyExc_OverflowError,
"formatted float is too long (precision too large?)");
PyMem_Free(tmp);
return -1;
}
strcpy(buf, tmp);
PyMem_Free(tmp);
return (int)len;
} }
/* _PyString_FormatLong emulates the format codes d, u, o, x and X, and /* _PyString_FormatLong emulates the format codes d, u, o, x and X, and
@ -4684,7 +4648,7 @@ formatchar(char *buf, size_t buflen, PyObject *v)
/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
FORMATBUFLEN is the length of the buffer in which the floats, ints, & FORMATBUFLEN is the length of the buffer in which the ints &
chars are formatted. XXX This is a magic number. Each formatting chars are formatted. XXX This is a magic number. Each formatting
routine does bounds checking to ensure no overflow, but a better routine does bounds checking to ensure no overflow, but a better
solution may be to malloc a buffer of appropriate size for each solution may be to malloc a buffer of appropriate size for each
@ -4754,7 +4718,7 @@ PyString_Format(PyObject *format, PyObject *args)
int sign; int sign;
Py_ssize_t len; Py_ssize_t len;
char formatbuf[FORMATBUFLEN]; char formatbuf[FORMATBUFLEN];
/* For format{float,int,char}() */ /* For format{int,char}() */
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
char *fmt_start = fmt; char *fmt_start = fmt;
Py_ssize_t argidx_start = argidx; Py_ssize_t argidx_start = argidx;
@ -5007,11 +4971,11 @@ PyString_Format(PyObject *format, PyObject *args)
case 'G': case 'G':
if (c == 'F') if (c == 'F')
c = 'f'; c = 'f';
pbuf = formatbuf; temp = formatfloat(v, flags, prec, c);
len = formatfloat(pbuf, sizeof(formatbuf), if (temp == NULL)
flags, prec, c, v);
if (len < 0)
goto error; goto error;
pbuf = PyString_AS_STRING(temp);
len = PyString_GET_SIZE(temp);
sign = 1; sign = 1;
if (flags & F_ZERO) if (flags & F_ZERO)
fill = '0'; fill = '0';

View File

@ -8302,68 +8302,32 @@ longtounicode(Py_UNICODE *buffer, size_t len, const char *format, long x)
shared with stringobject.c, converting from 8-bit to Unicode after the shared with stringobject.c, converting from 8-bit to Unicode after the
formatting is done. */ formatting is done. */
static int /* Returns a new reference to a PyUnicode object, or NULL on failure. */
formatfloat(Py_UNICODE *buf,
size_t buflen, static PyObject *
int flags, formatfloat(PyObject *v, int flags, int prec, int type)
int prec,
int type,
PyObject *v)
{ {
char *p;
PyObject *result;
double x; double x;
Py_ssize_t result;
char *tmp;
x = PyFloat_AsDouble(v); x = PyFloat_AsDouble(v);
if (x == -1.0 && PyErr_Occurred()) if (x == -1.0 && PyErr_Occurred())
return -1; return NULL;
if (prec < 0) if (prec < 0)
prec = 6; prec = 6;
#if SIZEOF_INT > 4
/* make sure that the decimal representation of precision really does
need at most 10 digits: platforms with sizeof(int) == 8 exist! */
if (prec > 0x7fffffff) {
PyErr_SetString(PyExc_OverflowError,
"outrageously large precision "
"for formatted float");
return -1;
}
#endif
if (type == 'f' && fabs(x) >= 1e50) if (type == 'f' && fabs(x) >= 1e50)
type = 'g'; type = 'g';
/* Worst case length calc to ensure no buffer overrun:
'g' formats: p = PyOS_double_to_string(x, type, prec,
fmt = %#.<prec>g (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL);
buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp if (p == NULL)
for any double rep.) return NULL;
len = 1 + prec + 1 + 2 + 5 = 9 + prec result = PyUnicode_FromStringAndSize(p, strlen(p));
PyMem_Free(p);
'f' formats: return result;
buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50)
len = 1 + 50 + 1 + prec = 52 + prec
If prec=0 the effective precision is 1 (the leading digit is
always given), therefore increase the length by one.
*/
if (((type == 'g' || type == 'G') &&
buflen <= (size_t)10 + (size_t)prec) ||
(type == 'f' && buflen <= (size_t)53 + (size_t)prec)) {
PyErr_SetString(PyExc_OverflowError,
"formatted float is too long (precision too large?)");
return -1;
}
tmp = PyOS_double_to_string(x, type, prec,
(flags&F_ALT)?Py_DTSF_ALT:0, NULL);
if (!tmp)
return -1;
result = strtounicode(buf, tmp);
PyMem_Free(tmp);
return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
} }
static PyObject* static PyObject*
@ -8516,7 +8480,7 @@ formatchar(Py_UNICODE *buf,
/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
FORMATBUFLEN is the length of the buffer in which the floats, ints, & FORMATBUFLEN is the length of the buffer in which the ints &
chars are formatted. XXX This is a magic number. Each formatting chars are formatted. XXX This is a magic number. Each formatting
routine does bounds checking to ensure no overflow, but a better routine does bounds checking to ensure no overflow, but a better
solution may be to malloc a buffer of appropriate size for each solution may be to malloc a buffer of appropriate size for each
@ -8587,7 +8551,7 @@ PyObject *PyUnicode_Format(PyObject *format,
Py_UNICODE *pbuf; Py_UNICODE *pbuf;
Py_UNICODE sign; Py_UNICODE sign;
Py_ssize_t len; Py_ssize_t len;
Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */ Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{int,char}() */
fmt++; fmt++;
if (*fmt == '(') { if (*fmt == '(') {
@ -8850,11 +8814,11 @@ PyObject *PyUnicode_Format(PyObject *format,
case 'G': case 'G':
if (c == 'F') if (c == 'F')
c = 'f'; c = 'f';
pbuf = formatbuf; temp = formatfloat(v, flags, prec, c);
len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), if (temp == NULL)
flags, prec, c, v);
if (len < 0)
goto onError; goto onError;
pbuf = PyUnicode_AS_UNICODE(temp);
len = PyUnicode_GET_SIZE(temp);
sign = 1; sign = 1;
if (flags & F_ZERO) if (flags & F_ZERO)
fill = '0'; fill = '0';