[Python-checkins] r59731 - in python/trunk: Doc/library/functions.rst Doc/library/math.rst Doc/library/stdtypes.rst Doc/reference/expressions.rst Lib/numbers.py Lib/test/test_builtin.py Lib/test/test_long.py Lib/test/test_math.py Modules/mathmodule.c Objects/floatobject.c Objects/intobject.c Objects/longobject.c Python/bltinmodule.c

jeffrey.yasskin python-checkins at python.org
Sat Jan 5 09:47:14 CET 2008


Author: jeffrey.yasskin
Date: Sat Jan  5 09:47:13 2008
New Revision: 59731

Modified:
   python/trunk/Doc/library/functions.rst
   python/trunk/Doc/library/math.rst
   python/trunk/Doc/library/stdtypes.rst
   python/trunk/Doc/reference/expressions.rst
   python/trunk/Lib/numbers.py
   python/trunk/Lib/test/test_builtin.py
   python/trunk/Lib/test/test_long.py
   python/trunk/Lib/test/test_math.py
   python/trunk/Modules/mathmodule.c
   python/trunk/Objects/floatobject.c
   python/trunk/Objects/intobject.c
   python/trunk/Objects/longobject.c
   python/trunk/Python/bltinmodule.c
Log:
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.


Modified: python/trunk/Doc/library/functions.rst
==============================================================================
--- python/trunk/Doc/library/functions.rst	(original)
+++ python/trunk/Doc/library/functions.rst	Sat Jan  5 09:47:13 2008
@@ -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])

Modified: python/trunk/Doc/library/math.rst
==============================================================================
--- python/trunk/Doc/library/math.rst	(original)
+++ python/trunk/Doc/library/math.rst	Sat Jan  5 09:47:13 2008
@@ -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)

Modified: python/trunk/Doc/library/stdtypes.rst
==============================================================================
--- python/trunk/Doc/library/stdtypes.rst	(original)
+++ python/trunk/Doc/library/stdtypes.rst	Sat Jan  5 09:47:13 2008
@@ -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
 

Modified: python/trunk/Doc/reference/expressions.rst
==============================================================================
--- python/trunk/Doc/reference/expressions.rst	(original)
+++ python/trunk/Doc/reference/expressions.rst	Sat Jan  5 09:47:13 2008
@@ -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:

Modified: python/trunk/Lib/numbers.py
==============================================================================
--- python/trunk/Lib/numbers.py	(original)
+++ python/trunk/Lib/numbers.py	Sat Jan  5 09:47:13 2008
@@ -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).
 

Modified: python/trunk/Lib/test/test_builtin.py
==============================================================================
--- python/trunk/Lib/test/test_builtin.py	(original)
+++ python/trunk/Lib/test/test_builtin.py	Sat Jan  5 09:47:13 2008
@@ -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)

Modified: python/trunk/Lib/test/test_long.py
==============================================================================
--- python/trunk/Lib/test/test_long.py	(original)
+++ python/trunk/Lib/test/test_long.py	Sat Jan  5 09:47:13 2008
@@ -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)
 

Modified: python/trunk/Lib/test/test_math.py
==============================================================================
--- python/trunk/Lib/test/test_math.py	(original)
+++ python/trunk/Lib/test/test_math.py	Sat Jan  5 09:47:13 2008
@@ -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)

Modified: python/trunk/Modules/mathmodule.c
==============================================================================
--- python/trunk/Modules/mathmodule.c	(original)
+++ python/trunk/Modules/mathmodule.c	Sat Jan  5 09:47:13 2008
@@ -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.")

Modified: python/trunk/Objects/floatobject.c
==============================================================================
--- python/trunk/Objects/floatobject.c	(original)
+++ python/trunk/Objects/floatobject.c	Sat Jan  5 09:47:13 2008
@@ -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},

Modified: python/trunk/Objects/intobject.c
==============================================================================
--- python/trunk/Objects/intobject.c	(original)
+++ python/trunk/Objects/intobject.c	Sat Jan  5 09:47:13 2008
@@ -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 */
 };

Modified: python/trunk/Objects/longobject.c
==============================================================================
--- python/trunk/Objects/longobject.c	(original)
+++ python/trunk/Objects/longobject.c	Sat Jan  5 09:47:13 2008
@@ -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 */
 };

Modified: python/trunk/Python/bltinmodule.c
==============================================================================
--- python/trunk/Python/bltinmodule.c	(original)
+++ python/trunk/Python/bltinmodule.c	Sat Jan  5 09:47:13 2008
@@ -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)


More information about the Python-checkins mailing list