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:
parent
5c456e6f45
commit
18cfada1ea
|
@ -1090,14 +1090,7 @@ 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
|
self.checkcall(format, "__mod__", value)
|
||||||
# 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)
|
|
||||||
|
|
||||||
def test_inplace_rewrites(self):
|
def test_inplace_rewrites(self):
|
||||||
# Check that strings don't copy and modify cached single-character strings
|
# Check that strings don't copy and modify cached single-character strings
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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';
|
||||||
|
|
Loading…
Reference in New Issue