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.
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 3236ccd..0133e5c 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -986,13 +986,10 @@
.. function:: round(x[, n])
Return the floating point value *x* rounded to *n* digits after the decimal
- point. If *n* is omitted, it defaults to zero. Values are rounded to the
- closest multiple of 10 to the power minus *n*; if two multiples are equally
- close, rounding is done toward the even choice (so, for example, both
- ``round(0.5)`` and ``round(-0.5)`` are ``0``, and ``round(1.5)`` is
- ``2``). Delegates to ``x.__round__(n)``.
-
- .. versionchanged:: 2.6
+ point. If *n* is omitted, it defaults to zero. The result is a floating point
+ number. Values are rounded to the closest multiple of 10 to the power minus
+ *n*; if two multiples are equally close, rounding is done away from 0 (so. for
+ example, ``round(0.5)`` is ``1.0`` and ``round(-0.5)`` is ``-1.0``).
.. function:: set([iterable])
diff --git a/Doc/library/math.rst b/Doc/library/math.rst
index 8c9f0f8..6c78104 100644
--- a/Doc/library/math.rst
+++ b/Doc/library/math.rst
@@ -26,9 +26,8 @@
.. function:: ceil(x)
- Return the ceiling of *x* as a float, the smallest integer value greater than
- or equal to *x*. If *x* is not a float, delegates to ``x.__ceil__()``, which
- should return an :class:`Integral` value.
+ Return the ceiling of *x* as a float, the smallest integer value greater than or
+ equal to *x*.
.. function:: copysign(x, y)
@@ -46,9 +45,8 @@
.. function:: floor(x)
- Return the floor of *x* as a float, the largest integer value less than or
- equal to *x*. If *x* is not a float, delegates to ``x.__floor__()``, which
- should return an :class:`Integral` value.
+ Return the floor of *x* as a float, the largest integer value less than or equal
+ to *x*.
.. function:: fmod(x, y)
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 7352a1d..7a0e24d 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -341,11 +341,11 @@
pair: C; language
Conversion from floating point to (long or plain) integer may round or
- truncate as in C.
+ truncate as in C; see functions :func:`math.floor` and :func:`math.ceil` for
+ well-defined conversions.
.. deprecated:: 2.6
- Instead, convert floats to long explicitly with :func:`trunc`,
- :func:`math.floor`, or :func:`math.ceil`.
+ Instead, convert floats to long explicitly with :func:`trunc`.
(3)
See :ref:`built-in-funcs` for a full description.
@@ -369,19 +369,19 @@
All :class:`numbers.Real` types (:class:`int`, :class:`long`, and
:class:`float`) also include the following operations:
-+--------------------+--------------------------------+--------+
-| Operation | Result | Notes |
-+====================+================================+========+
-| ``trunc(x)`` | *x* truncated to Integral | |
-+--------------------+--------------------------------+--------+
-| ``round(x[, n])`` | *x* rounded to n digits, | |
-| | rounding half to even. If n is | |
-| | omitted, it defaults to 0. | |
-+--------------------+--------------------------------+--------+
-| ``math.floor(x)`` | the greatest Integral <= *x* | |
-+--------------------+--------------------------------+--------+
-| ``math.ceil(x)`` | the least Integral >= *x* | |
-+--------------------+--------------------------------+--------+
++--------------------+------------------------------------+--------+
+| Operation | Result | Notes |
++====================+====================================+========+
+| ``trunc(x)`` | *x* truncated to Integral | |
++--------------------+------------------------------------+--------+
+| ``round(x[, n])`` | *x* rounded to n digits, | |
+| | rounding half to even. If n is | |
+| | omitted, it defaults to 0. | |
++--------------------+------------------------------------+--------+
+| ``math.floor(x)`` | the greatest integral float <= *x* | |
++--------------------+------------------------------------+--------+
+| ``math.ceil(x)`` | the least integral float >= *x* | |
++--------------------+------------------------------------+--------+
.. XXXJH exceptions: overflow (when? what operations?) zerodivision
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
index 9c416f8..ea2bb1a 100644
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -801,8 +801,7 @@
raised).
Raising ``0.0`` to a negative power results in a :exc:`ZeroDivisionError`.
-Raising a negative number to a fractional power results in a :class:`complex`
-number. (Since Python 2.6. In earlier versions it raised a :exc:`ValueError`.)
+Raising a negative number to a fractional power results in a :exc:`ValueError`.
.. _unary:
diff --git a/Lib/numbers.py b/Lib/numbers.py
index d23fa34..3c13290 100644
--- a/Lib/numbers.py
+++ b/Lib/numbers.py
@@ -189,25 +189,6 @@
"""
raise NotImplementedError
- @abstractmethod
- def __floor__(self):
- """Finds the greatest Integral <= self."""
- raise NotImplementedError
-
- @abstractmethod
- def __ceil__(self):
- """Finds the least Integral >= self."""
- raise NotImplementedError
-
- @abstractmethod
- def __round__(self, ndigits=None):
- """Rounds self to ndigits decimal places, defaulting to 0.
-
- If ndigits is omitted or None, returns an Integral, otherwise
- returns a Real. Rounds half toward even.
- """
- raise NotImplementedError
-
def __divmod__(self, other):
"""divmod(self, other): The pair (self // other, self % other).
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 255fb96..d56e6ff 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -1456,13 +1456,12 @@
else:
self.assertAlmostEqual(pow(x, y, z), 24.0)
- self.assertAlmostEqual(pow(-1, 0.5), 1j)
- self.assertAlmostEqual(pow(-1, 1./3), 0.5 + 0.8660254037844386j)
-
self.assertRaises(TypeError, pow, -1, -2, 3)
self.assertRaises(ValueError, pow, 1, 2, 0)
self.assertRaises(TypeError, pow, -1L, -2L, 3L)
self.assertRaises(ValueError, pow, 1L, 2L, 0L)
+ # Will return complex in 3.0:
+ self.assertRaises(ValueError, pow, -342.43, 0.234)
self.assertRaises(TypeError, pow)
@@ -1664,11 +1663,11 @@
self.assertEqual(type(round(-8.0, 0)), float)
self.assertEqual(type(round(-8.0, 1)), float)
- # Check even / odd rounding behaviour
+ # Check half rounding behaviour.
self.assertEqual(round(5.5), 6)
- self.assertEqual(round(6.5), 6)
+ self.assertEqual(round(6.5), 7)
self.assertEqual(round(-5.5), -6)
- self.assertEqual(round(-6.5), -6)
+ self.assertEqual(round(-6.5), -7)
# Check behavior on ints
self.assertEqual(round(0), 0)
@@ -1686,8 +1685,8 @@
# test generic rounding delegation for reals
class TestRound(object):
- def __round__(self):
- return 23
+ def __float__(self):
+ return 23.0
class TestNoRound(object):
pass
@@ -1695,13 +1694,12 @@
self.assertEqual(round(TestRound()), 23)
self.assertRaises(TypeError, round, 1, 2, 3)
- # XXX: This is not ideal, but see the comment in builtin_round().
- self.assertRaises(AttributeError, round, TestNoRound())
+ self.assertRaises(TypeError, round, TestNoRound())
t = TestNoRound()
- t.__round__ = lambda *args: args
- self.assertEquals((), round(t))
- self.assertEquals((0,), round(t, 0))
+ t.__float__ = lambda *args: args
+ self.assertRaises(TypeError, round, t)
+ self.assertRaises(TypeError, round, t, 0)
def test_setattr(self):
setattr(sys, 'spam', 1)
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index d745350..1709de5 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -385,9 +385,7 @@
"1. ** huge", "huge ** 1.", "1. ** mhuge", "mhuge ** 1.",
"math.sin(huge)", "math.sin(mhuge)",
"math.sqrt(huge)", "math.sqrt(mhuge)", # should do better
- # math.floor() of an int returns an int now
- ##"math.floor(huge)", "math.floor(mhuge)",
- ]:
+ "math.floor(huge)", "math.floor(mhuge)"]:
self.assertRaises(OverflowError, eval, test, namespace)
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index 5313c3c..16f0f4d 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -63,8 +63,8 @@
self.ftest('ceil(-1.5)', math.ceil(-1.5), -1)
class TestCeil(object):
- def __ceil__(self):
- return 42
+ def __float__(self):
+ return 41.3
class TestNoCeil(object):
pass
self.ftest('ceil(TestCeil())', math.ceil(TestCeil()), 42)
@@ -123,8 +123,8 @@
self.ftest('floor(-1.23e167)', math.floor(-1.23e167), -1.23e167)
class TestFloor(object):
- def __floor__(self):
- return 42
+ def __float__(self):
+ return 42.3
class TestNoFloor(object):
pass
self.ftest('floor(TestFloor())', math.floor(TestFloor()), 42)
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 44a9d93..5e52e78 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -107,28 +107,9 @@
FUNC2(atan2, atan2,
"atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n"
"Unlike atan(y/x), the signs of both x and y are considered.")
-
-static PyObject * math_ceil(PyObject *self, PyObject *number) {
- static PyObject *ceil_str = NULL;
- PyObject *method;
-
- if (ceil_str == NULL) {
- ceil_str = PyString_FromString("__ceil__");
- if (ceil_str == NULL)
- return NULL;
- }
-
- method = _PyType_Lookup(Py_Type(number), ceil_str);
- if (method == NULL)
- return math_1(number, ceil);
- else
- return PyObject_CallFunction(method, "O", number);
-}
-
-PyDoc_STRVAR(math_ceil_doc,
- "ceil(x)\n\nReturn the ceiling of x as a float.\n"
- "This is the smallest integral value >= x.");
-
+FUNC1(ceil, ceil,
+ "ceil(x)\n\nReturn the ceiling of x as a float.\n"
+ "This is the smallest integral value >= x.")
FUNC1(cos, cos,
"cos(x)\n\nReturn the cosine of x (measured in radians).")
FUNC1(cosh, cosh,
@@ -147,28 +128,9 @@
"exp(x)\n\nReturn e raised to the power of x.")
FUNC1(fabs, fabs,
"fabs(x)\n\nReturn the absolute value of the float x.")
-
-static PyObject * math_floor(PyObject *self, PyObject *number) {
- static PyObject *floor_str = NULL;
- PyObject *method;
-
- if (floor_str == NULL) {
- floor_str = PyString_FromString("__floor__");
- if (floor_str == NULL)
- return NULL;
- }
-
- method = _PyType_Lookup(Py_Type(number), floor_str);
- if (method == NULL)
- return math_1(number, floor);
- else
- return PyObject_CallFunction(method, "O", number);
-}
-
-PyDoc_STRVAR(math_floor_doc,
- "floor(x)\n\nReturn the floor of x as a float.\n"
- "This is the largest integral value <= x.");
-
+FUNC1(floor, floor,
+ "floor(x)\n\nReturn the floor of x as a float.\n"
+ "This is the largest integral value <= x.")
FUNC2(fmod, fmod,
"fmod(x,y)\n\nReturn fmod(x, y), according to platform C."
" x % y may differ.")
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 574b96a..ff23d33 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -986,10 +986,9 @@
* 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.
@@ -1099,54 +1098,6 @@
}
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)
{
if (PyFloat_CheckExact(v))
@@ -1344,9 +1295,6 @@
"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},
diff --git a/Objects/intobject.c b/Objects/intobject.c
index 96d7f76..edb8e4f 100644
--- a/Objects/intobject.c
+++ b/Objects/intobject.c
@@ -1056,43 +1056,11 @@
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 */
};
diff --git a/Objects/longobject.c b/Objects/longobject.c
index eea5c3b..1094670 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -3370,45 +3370,11 @@
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 */
};
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index a7d77de..84a0008 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1926,31 +1926,39 @@
static PyObject *
builtin_round(PyObject *self, PyObject *args, PyObject *kwds)
{
-#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */
- int ndigits = UNDEF_NDIGITS;
+ double number;
+ double f;
+ int ndigits = 0;
+ int i;
static char *kwlist[] = {"number", "ndigits", 0};
- PyObject *number;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:round",
- kwlist, &number, &ndigits))
- return NULL;
-
- // The py3k branch gets better errors for this by using
- // _PyType_Lookup(), but since float's mro isn't set in py2.6,
- // we just use PyObject_CallMethod here.
- if (ndigits == UNDEF_NDIGITS)
- return PyObject_CallMethod(number, "__round__", "");
- else
- return PyObject_CallMethod(number, "__round__", "i", ndigits);
-#undef UNDEF_NDIGITS
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|i:round",
+ kwlist, &number, &ndigits))
+ return NULL;
+ f = 1.0;
+ i = abs(ndigits);
+ while (--i >= 0)
+ f = f*10.0;
+ if (ndigits < 0)
+ number /= f;
+ else
+ number *= f;
+ if (number >= 0.0)
+ number = floor(number + 0.5);
+ else
+ number = ceil(number - 0.5);
+ if (ndigits < 0)
+ number *= f;
+ else
+ number /= f;
+ return PyFloat_FromDouble(number);
}
PyDoc_STRVAR(round_doc,
"round(number[, ndigits]) -> floating point number\n\
\n\
Round a number to a given precision in decimal digits (default 0 digits).\n\
-This returns an int when called with one argument, otherwise a float.\n\
-Precision may be negative.");
+This always returns a floating point number. Precision may be negative.");
static PyObject *
builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds)