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

Reply via email to