Continue rolling back pep-3141 changes that changed behavior from 2.5. This

round included:
 * Revert round to its 2.6 behavior (half away from 0).
 * Because round, floor, and ceil always return float again, it's no
   longer necessary to have them delegate to __xxx___, so I've ripped
   that out of their implementations and the Real ABC. This also helps
   in implementing types that work in both 2.6 and 3.0: you return int
   from the __xxx__ methods, and let it get enabled by the version
   upgrade.
 * Make pow(-1, .5) raise a ValueError again.
This commit is contained in:
Jeffrey Yasskin 2008-01-05 08:47:13 +00:00
parent f7476c4d46
commit 9871d8fe22
13 changed files with 75 additions and 252 deletions

View file

@ -986,10 +986,9 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* bugs so we have to figure it out ourselves.
*/
if (iw != floor(iw)) {
/* Negative numbers raised to fractional powers
* become complex.
*/
return PyComplex_Type.tp_as_number->nb_power(v, w, z);
PyErr_SetString(PyExc_ValueError, "negative number "
"cannot be raised to a fractional power");
return NULL;
}
/* iw is an exact integer, albeit perhaps a very large one.
* -1 raised to an exact integer should never be exceptional.
@ -1098,54 +1097,6 @@ float_trunc(PyObject *v)
return PyLong_FromDouble(wholepart);
}
static PyObject *
float_round(PyObject *v, PyObject *args)
{
#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */
double x;
double f;
double flr, cil;
double rounded;
int i;
int ndigits = UNDEF_NDIGITS;
if (!PyArg_ParseTuple(args, "|i", &ndigits))
return NULL;
x = PyFloat_AsDouble(v);
if (ndigits != UNDEF_NDIGITS) {
f = 1.0;
i = abs(ndigits);
while (--i >= 0)
f = f*10.0;
if (ndigits < 0)
x /= f;
else
x *= f;
}
flr = floor(x);
cil = ceil(x);
if (x-flr > 0.5)
rounded = cil;
else if (x-flr == 0.5)
rounded = fmod(flr, 2) == 0 ? flr : cil;
else
rounded = flr;
if (ndigits != UNDEF_NDIGITS) {
if (ndigits < 0)
rounded *= f;
else
rounded /= f;
}
return PyFloat_FromDouble(rounded);
#undef UNDEF_NDIGITS
}
static PyObject *
float_float(PyObject *v)
{
@ -1344,9 +1295,6 @@ static PyMethodDef float_methods[] = {
"Returns self, the complex conjugate of any float."},
{"__trunc__", (PyCFunction)float_trunc, METH_NOARGS,
"Returns the Integral closest to x between 0 and x."},
{"__round__", (PyCFunction)float_round, METH_VARARGS,
"Returns the Integral closest to x, rounding half toward even.\n"
"When an argument is passed, works like built-in round(x, ndigits)."},
{"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS},
{"__getformat__", (PyCFunction)float_getformat,
METH_O|METH_CLASS, float_getformat_doc},

View file

@ -1056,43 +1056,11 @@ int_getN(PyIntObject *v, void *context) {
return PyInt_FromLong((intptr_t)context);
}
static PyObject *
int_round(PyObject *self, PyObject *args)
{
#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */
int ndigits = UNDEF_NDIGITS;
double x;
PyObject *res;
if (!PyArg_ParseTuple(args, "|i", &ndigits))
return NULL;
if (ndigits == UNDEF_NDIGITS)
return int_float((PyIntObject *)self);
/* If called with two args, defer to float.__round__(). */
x = (double) PyInt_AS_LONG(self);
self = PyFloat_FromDouble(x);
if (self == NULL)
return NULL;
res = PyObject_CallMethod(self, "__round__", "i", ndigits);
Py_DECREF(self);
return res;
#undef UNDEF_NDIGITS
}
static PyMethodDef int_methods[] = {
{"conjugate", (PyCFunction)int_int, METH_NOARGS,
"Returns self, the complex conjugate of any int."},
{"__trunc__", (PyCFunction)int_int, METH_NOARGS,
"Truncating an Integral returns itself."},
{"__floor__", (PyCFunction)int_float, METH_NOARGS,
"Flooring an Integral returns itself."},
{"__ceil__", (PyCFunction)int_float, METH_NOARGS,
"Ceiling of an Integral returns itself."},
{"__round__", (PyCFunction)int_round, METH_VARARGS,
"Rounding an Integral returns itself.\n"
"Rounding with an ndigits arguments defers to float.__round__."},
{"__getnewargs__", (PyCFunction)int_getnewargs, METH_NOARGS},
{NULL, NULL} /* sentinel */
};

View file

@ -3370,45 +3370,11 @@ long_getN(PyLongObject *v, void *context) {
return PyLong_FromLong((intptr_t)context);
}
static PyObject *
long_round(PyObject *self, PyObject *args)
{
#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */
int ndigits = UNDEF_NDIGITS;
double x;
PyObject *res;
if (!PyArg_ParseTuple(args, "|i", &ndigits))
return NULL;
if (ndigits == UNDEF_NDIGITS)
return long_float(self);
/* If called with two args, defer to float.__round__(). */
x = PyLong_AsDouble(self);
if (x == -1.0 && PyErr_Occurred())
return NULL;
self = PyFloat_FromDouble(x);
if (self == NULL)
return NULL;
res = PyObject_CallMethod(self, "__round__", "i", ndigits);
Py_DECREF(self);
return res;
#undef UNDEF_NDIGITS
}
static PyMethodDef long_methods[] = {
{"conjugate", (PyCFunction)long_long, METH_NOARGS,
"Returns self, the complex conjugate of any long."},
{"__trunc__", (PyCFunction)long_long, METH_NOARGS,
"Truncating an Integral returns itself."},
{"__floor__", (PyCFunction)long_float, METH_NOARGS,
"Flooring an Integral returns itself."},
{"__ceil__", (PyCFunction)long_float, METH_NOARGS,
"Ceiling of an Integral returns itself."},
{"__round__", (PyCFunction)long_round, METH_VARARGS,
"Rounding an Integral returns itself.\n"
"Rounding with an ndigits arguments defers to float.__round__."},
{"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS},
{NULL, NULL} /* sentinel */
};