summaryrefslogtreecommitdiff
path: root/Python/bltinmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/bltinmodule.c')
-rw-r--r--Python/bltinmodule.c85
1 files changed, 54 insertions, 31 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 57d9df8e84..764ae87ed9 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -8,6 +8,7 @@
#include "eval.h"
#include <ctype.h>
+#include <float.h> /* for DBL_MANT_DIG and friends */
#ifdef RISCOS
#include "unixstuff.h"
@@ -1489,7 +1490,7 @@ PyDoc_STRVAR(open_doc,
"open(name[, mode[, buffering]]) -> file object\n\
\n\
Open a file using the file() type, returns a file object. This is the\n\
-preferred way to open a file.");
+preferred way to open a file. See file.__doc__ for further information.");
static PyObject *
@@ -1796,7 +1797,7 @@ handle_range_longs(PyObject *self, PyObject *args)
PyObject *curnum = NULL;
PyObject *v = NULL;
long bign;
- int i, n;
+ Py_ssize_t i, n;
int cmp_result;
PyObject *zero = PyLong_FromLong(0);
@@ -1864,7 +1865,7 @@ handle_range_longs(PyObject *self, PyObject *args)
Py_DECREF(neg_step);
}
- n = (int)bign;
+ n = (Py_ssize_t)bign;
if (bign < 0 || (long)n != bign) {
PyErr_SetString(PyExc_OverflowError,
"range() result has too many items");
@@ -1944,7 +1945,7 @@ builtin_range(PyObject *self, PyObject *args)
{
long ilow = 0, ihigh = 0, istep = 1;
long bign;
- int i, n;
+ Py_ssize_t i, n;
PyObject *v;
@@ -1973,7 +1974,7 @@ builtin_range(PyObject *self, PyObject *args)
bign = get_len_of_range(ilow, ihigh, istep);
else
bign = get_len_of_range(ihigh, ilow, -istep);
- n = (int)bign;
+ n = (Py_ssize_t)bign;
if (bign < 0 || (long)n != bign) {
PyErr_SetString(PyExc_OverflowError,
"range() result has too many items");
@@ -2151,36 +2152,47 @@ For most object types, eval(repr(object)) == object.");
static PyObject *
builtin_round(PyObject *self, PyObject *args, PyObject *kwds)
{
- double number, abs_number, abs_result;
- double f;
- int ndigits = 0;
- int i;
+ double x;
+ PyObject *o_ndigits = NULL;
+ Py_ssize_t ndigits;
static char *kwlist[] = {"number", "ndigits", 0};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|i:round",
- kwlist, &number, &ndigits))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|O:round",
+ kwlist, &x, &o_ndigits))
return NULL;
- f = 1.0;
- i = abs(ndigits);
- while (--i >= 0)
- f = f*10.0;
- if (ndigits < 0)
- number /= f;
- else
- number *= f;
- /* round `number` to nearest integer, rounding halves away from zero */
- abs_number = fabs(number);
- abs_result = floor(abs_number);
- if (abs_number - abs_result >= 0.5)
- abs_result += 1.0;
- number = copysign(abs_result, number);
+ if (o_ndigits == NULL) {
+ /* second argument defaults to 0 */
+ ndigits = 0;
+ }
+ else {
+ /* interpret 2nd argument as a Py_ssize_t; clip on overflow */
+ ndigits = PyNumber_AsSsize_t(o_ndigits, NULL);
+ if (ndigits == -1 && PyErr_Occurred())
+ return NULL;
+ }
- if (ndigits < 0)
- number *= f;
+ /* nans, infinities and zeros round to themselves */
+ if (!Py_IS_FINITE(x) || x == 0.0)
+ return PyFloat_FromDouble(x);
+
+ /* Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x
+ always rounds to itself. For ndigits < NDIGITS_MIN, x always
+ rounds to +-0.0. Here 0.30103 is an upper bound for log10(2). */
+#define NDIGITS_MAX ((int)((DBL_MANT_DIG-DBL_MIN_EXP) * 0.30103))
+#define NDIGITS_MIN (-(int)((DBL_MAX_EXP + 1) * 0.30103))
+ if (ndigits > NDIGITS_MAX)
+ /* return x */
+ return PyFloat_FromDouble(x);
+ else if (ndigits < NDIGITS_MIN)
+ /* return 0.0, but with sign of x */
+ return PyFloat_FromDouble(0.0*x);
else
- number /= f;
- return PyFloat_FromDouble(number);
+ /* finite x, and ndigits is not unreasonably large */
+ /* _Py_double_round is defined in floatobject.c */
+ return _Py_double_round(x, (int)ndigits);
+#undef NDIGITS_MAX
+#undef NDIGITS_MIN
}
PyDoc_STRVAR(round_doc,
@@ -2388,6 +2400,15 @@ builtin_sum(PyObject *self, PyObject *args)
}
break;
}
+ /* It's tempting to use PyNumber_InPlaceAdd instead of
+ PyNumber_Add here, to avoid quadratic running time
+ when doing 'sum(list_of_lists, [])'. However, this
+ would produce a change in behaviour: a snippet like
+
+ empty = []
+ sum([[x] for x in range(10)], empty)
+
+ would change the value of empty. */
temp = PyNumber_Add(result, item);
Py_DECREF(result);
Py_DECREF(item);
@@ -2477,8 +2498,10 @@ builtin_zip(PyObject *self, PyObject *args)
len = -1; /* unknown */
for (i = 0; i < itemsize; ++i) {
PyObject *item = PyTuple_GET_ITEM(args, i);
- Py_ssize_t thislen = _PyObject_LengthHint(item, -1);
+ Py_ssize_t thislen = _PyObject_LengthHint(item, -2);
if (thislen < 0) {
+ if (thislen == -1)
+ return NULL;
len = -1;
break;
}
@@ -2664,7 +2687,7 @@ _PyBuiltin_Init(void)
SETBUILTIN("True", Py_True);
SETBUILTIN("basestring", &PyBaseString_Type);
SETBUILTIN("bool", &PyBool_Type);
- /* SETBUILTIN("memoryview", &PyMemoryView_Type); */
+ SETBUILTIN("memoryview", &PyMemoryView_Type);
SETBUILTIN("bytearray", &PyByteArray_Type);
SETBUILTIN("bytes", &PyString_Type);
SETBUILTIN("buffer", &PyBuffer_Type);