summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/string_tests.py9
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/stringobject.c78
-rw-r--r--Objects/unicodeobject.c78
4 files changed, 47 insertions, 122 deletions
diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py
index e66855d..caff3d4 100644
--- a/Lib/test/string_tests.py
+++ b/Lib/test/string_tests.py
@@ -1090,14 +1090,7 @@ class MixinStrUnicodeUserStringTest:
value = 0.01
for x in xrange(60):
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):
# Check that strings don't copy and modify cached single-character strings
diff --git a/Misc/NEWS b/Misc/NEWS
index 356e3a1..58b7057 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,10 @@ What's New in Python 2.7 alpha 1
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.
- Issue #7362: Give a proper error message for def f((x)=3): pass.
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 4746b3c..1d9ba8c 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -4379,72 +4379,36 @@ getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx)
#define F_ALT (1<<3)
#define F_ZERO (1<<4)
-Py_LOCAL_INLINE(int)
-formatfloat(char *buf, size_t buflen, int flags,
- int prec, int type, PyObject *v)
+/* Returns a new reference to a PyString object, or NULL on failure. */
+
+static PyObject *
+formatfloat(PyObject *v, int flags, int prec, int type)
{
- char *tmp;
+ char *p;
+ PyObject *result;
double x;
- Py_ssize_t len;
x = PyFloat_AsDouble(v);
if (x == -1.0 && PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError, "float argument required, "
"not %.200s", Py_TYPE(v)->tp_name);
- return -1;
+ return NULL;
}
+
if (prec < 0)
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)
type = 'g';
- /* Worst case length calc to ensure no buffer overrun:
- 'g' formats:
- fmt = %#.<prec>g
- buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
- for any double rep.)
- len = 1 + prec + 1 + 2 + 5 = 9 + prec
+ p = PyOS_double_to_string(x, type, prec,
+ (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL);
- 'f' formats:
- 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;
- 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;
+ if (p == NULL)
+ return NULL;
+ result = PyString_FromStringAndSize(p, strlen(p));
+ PyMem_Free(p);
+ return result;
}
/* _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, ...)
- 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
routine does bounds checking to ensure no overflow, but a better
solution may be to malloc a buffer of appropriate size for each
@@ -4754,7 +4718,7 @@ PyString_Format(PyObject *format, PyObject *args)
int sign;
Py_ssize_t len;
char formatbuf[FORMATBUFLEN];
- /* For format{float,int,char}() */
+ /* For format{int,char}() */
#ifdef Py_USING_UNICODE
char *fmt_start = fmt;
Py_ssize_t argidx_start = argidx;
@@ -5007,11 +4971,11 @@ PyString_Format(PyObject *format, PyObject *args)
case 'G':
if (c == 'F')
c = 'f';
- pbuf = formatbuf;
- len = formatfloat(pbuf, sizeof(formatbuf),
- flags, prec, c, v);
- if (len < 0)
+ temp = formatfloat(v, flags, prec, c);
+ if (temp == NULL)
goto error;
+ pbuf = PyString_AS_STRING(temp);
+ len = PyString_GET_SIZE(temp);
sign = 1;
if (flags & F_ZERO)
fill = '0';
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 65c10b1..401f7be 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -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
formatting is done. */
-static int
-formatfloat(Py_UNICODE *buf,
- size_t buflen,
- int flags,
- int prec,
- int type,
- PyObject *v)
+/* Returns a new reference to a PyUnicode object, or NULL on failure. */
+
+static PyObject *
+formatfloat(PyObject *v, int flags, int prec, int type)
{
+ char *p;
+ PyObject *result;
double x;
- Py_ssize_t result;
- char *tmp;
x = PyFloat_AsDouble(v);
if (x == -1.0 && PyErr_Occurred())
- return -1;
+ return NULL;
+
if (prec < 0)
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)
type = 'g';
- /* Worst case length calc to ensure no buffer overrun:
-
- 'g' formats:
- fmt = %#.<prec>g
- buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
- for any double rep.)
- len = 1 + prec + 1 + 2 + 5 = 9 + prec
-
- 'f' formats:
- 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);
+ p = PyOS_double_to_string(x, type, prec,
+ (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL);
+ if (p == NULL)
+ return NULL;
+ result = PyUnicode_FromStringAndSize(p, strlen(p));
+ PyMem_Free(p);
+ return result;
}
static PyObject*
@@ -8516,7 +8480,7 @@ formatchar(Py_UNICODE *buf,
/* 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
routine does bounds checking to ensure no overflow, but a better
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 sign;
Py_ssize_t len;
- Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */
+ Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{int,char}() */
fmt++;
if (*fmt == '(') {
@@ -8850,11 +8814,11 @@ PyObject *PyUnicode_Format(PyObject *format,
case 'G':
if (c == 'F')
c = 'f';
- pbuf = formatbuf;
- len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE),
- flags, prec, c, v);
- if (len < 0)
+ temp = formatfloat(v, flags, prec, c);
+ if (temp == NULL)
goto onError;
+ pbuf = PyUnicode_AS_UNICODE(temp);
+ len = PyUnicode_GET_SIZE(temp);
sign = 1;
if (flags & F_ZERO)
fill = '0';