This patch fixes the previously added truncate, and also fixes round
behavior. The two argument version of round is not currently handling
the round toward even case.
Keir
Index: Python/bltinmodule.c
===================================================================
--- Python/bltinmodule.c (revision 57303)
+++ Python/bltinmodule.c (working copy)
@@ -1376,52 +1376,41 @@
double number;
double f;
int ndigits = 0;
- int i;
static char *kwlist[] = {"number", "ndigits", 0};
- PyObject* real;
+ PyObject* real, *pyfloat;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:round",
kwlist, &real, &ndigits))
return NULL;
- if (ndigits == 0) {
+ if (ndigits == 0 && PyTuple_GET_SIZE(args) == 1) {
PyObject *res;
PyObject *d = PyObject_GetAttrString(real, "__round__");
- if (d == NULL && !PyFloat_Check(real)) {
+ if (d == NULL) {
PyErr_SetString(PyExc_TypeError,
"round() argument must have __round__ attribute or be a float");
return NULL;
}
- if (d == NULL) {
- PyErr_Clear();
- } else {
- res = PyObject_CallFunction(d, "");
- Py_DECREF(d);
- return res;
- }
- } else if (!PyFloat_Check(real)) {
+ res = PyObject_CallFunction(d, "");
+ Py_DECREF(d);
+ return res;
+ }
+
+ pyfloat = PyNumber_Float(real);
+ if (pyfloat == NULL) {
PyErr_SetString(PyExc_TypeError,
"round() argument must have __round__ attribute or be a float");
return NULL;
- }
-
- number = PyFloat_AsDouble(real);
- f = 1.0;
- i = abs(ndigits);
- while (--i >= 0)
- f = f*10.0;
- if (ndigits < 0)
- number /= f;
- else
- number *= f;
+ }
+ number = PyFloat_AsDouble(pyfloat);
+ Py_DECREF(pyfloat);
+ f = pow(10.0, ndigits);
+ 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;
+ number /= f;
return PyFloat_FromDouble(number);
}
Index: Objects/longobject.c
===================================================================
--- Objects/longobject.c (revision 57303)
+++ Objects/longobject.c (working copy)
@@ -3595,6 +3595,14 @@
static PyMethodDef long_methods[] = {
{"conjugate", (PyCFunction)long_long, METH_NOARGS,
"Returns self, the complex conjugate of any int."},
+ {"__trunc__", (PyCFunction)long_long, METH_NOARGS,
+ "Truncating an Integral returns itself."},
+ {"__floor__", (PyCFunction)long_long, METH_NOARGS,
+ "Flooring an Integral returns itself."},
+ {"__ceil__", (PyCFunction)long_long, METH_NOARGS,
+ "Ceiling of an Integral returns itself."},
+ {"__round__", (PyCFunction)long_long, METH_NOARGS,
+ "Rounding an Integral returns itself."},
{"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
Index: Objects/floatobject.c
===================================================================
--- Objects/floatobject.c (revision 57303)
+++ Objects/floatobject.c (working copy)
@@ -743,16 +743,9 @@
}
static PyObject *
-float_long(PyObject *v)
+float_trunc(PyObject *v)
{
double x = PyFloat_AsDouble(v);
- return PyLong_FromDouble(x);
-}
-
-static PyObject *
-float_int(PyObject *v)
-{
- double x = PyFloat_AsDouble(v);
double wholepart; /* integral portion of x, rounded toward 0 */
(void)modf(x, &wholepart);
@@ -776,6 +769,27 @@
}
static PyObject *
+float_round(PyObject *v)
+{
+ double x;
+ double flr, cil;
+ double rounded;
+
+ x = PyFloat_AsDouble(v);
+ 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;
+
+ return PyLong_FromDouble(rounded);
+}
+
+static PyObject *
float_float(PyObject *v)
{
if (PyFloat_CheckExact(v))
@@ -976,6 +990,10 @@
static PyMethodDef float_methods[] = {
{"conjugate", (PyCFunction)float_float, METH_NOARGS,
"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_NOARGS,
+ "returns the Integral closest to x, rounding half toward even."},
{"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS},
{"__getformat__", (PyCFunction)float_getformat,
METH_O|METH_CLASS, float_getformat_doc},
@@ -1020,8 +1038,8 @@
0, /*nb_xor*/
0, /*nb_or*/
(coercion)0, /*nb_coerce*/
- float_int, /*nb_int*/
- float_long, /*nb_long*/
+ float_trunc, /*nb_int*/
+ float_trunc, /*nb_long*/
float_float, /*nb_float*/
0, /* nb_oct */
0, /* nb_hex */
Index: Lib/test/test_builtin.py
===================================================================
--- Lib/test/test_builtin.py (revision 57303)
+++ Lib/test/test_builtin.py (working copy)
@@ -1440,6 +1440,7 @@
def test_round(self):
self.assertEqual(round(0.0), 0.0)
+ self.assertEqual(type(round(0.0)), int)
self.assertEqual(round(1.0), 1.0)
self.assertEqual(round(10.0), 10.0)
self.assertEqual(round(1000000000.0), 1000000000.0)
@@ -1468,7 +1469,17 @@
self.assertEqual(round(-999999999.9), -1000000000.0)
self.assertEqual(round(-8.0, -1), -10.0)
+ self.assertEqual(type(round(-8.0, -1)), float)
+ self.assertEqual(type(round(-8.0, 0)), float)
+ self.assertEqual(type(round(-8.0, 1)), float)
+
+ # Check even / odd rounding behaviour
+ self.assertEqual(round(5.5), 6)
+ self.assertEqual(round(6.5), 6)
+ self.assertEqual(round(-5.5), -6)
+ self.assertEqual(round(-6.5), -6)
+
# test new kwargs
self.assertEqual(round(number=-8.0, ndigits=-1), -10.0)
@@ -1529,6 +1540,18 @@
self.assertRaises(ValueError, sum, BadSeq())
def test_trunc(self):
+
+ self.assertEqual(trunc(1), 1)
+ self.assertEqual(trunc(-1), -1)
+ self.assertEqual(type(trunc(1)), int)
+ self.assertEqual(type(trunc(1.5)), int)
+ self.assertEqual(trunc(1.5), 1)
+ self.assertEqual(trunc(-1.5), -1)
+ self.assertEqual(trunc(1.999999), 1)
+ self.assertEqual(trunc(-1.999999), -1)
+ self.assertEqual(trunc(-0.999999), -0)
+ self.assertEqual(trunc(-100.999), -100)
+
class TestTrunc:
def __trunc__(self):
return 23
_______________________________________________
Python-3000 mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe:
http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com