From 0b3675036327983d29b23a6aede94e649da536b6 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 29 Oct 2019 17:31:07 +0300 Subject: [PATCH 1/3] bpo-38629: implement __floor__ and __ceil__ for float --- Lib/test/test_float.py | 28 ++++++++++++++ .../2019-10-29-17-11-15.bpo-38629.3qinhF.rst | 2 + Objects/clinic/floatobject.c.h | 38 ++++++++++++++++++- Objects/floatobject.c | 30 +++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index b656582538e875..9651281e24edbe 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -312,6 +312,34 @@ def assertEqualAndEqualSign(self, a, b): # distinguishes -0.0 and 0.0. self.assertEqual((a, copysign(1.0, a)), (b, copysign(1.0, b))) + def test_float_floor(self): + self.assertIsInstance(float(0.5).__floor__(), int) + self.assertEqual(float(0.5).__floor__(), 0) + self.assertEqual(float(1.0).__floor__(), 1) + self.assertEqual(float(1.5).__floor__(), 1) + self.assertEqual(float(-0.5).__floor__(), -1) + self.assertEqual(float(-1.0).__floor__(), -1) + self.assertEqual(float(-1.5).__floor__(), -2) + self.assertEqual(float(1.23e167).__floor__(), 1.23e167) + self.assertEqual(float(-1.23e167).__floor__(), -1.23e167) + self.assertRaises(ValueError, float("nan").__floor__) + self.assertRaises(OverflowError, float("inf").__floor__) + self.assertRaises(OverflowError, float("-inf").__floor__) + + def test_float_ceil(self): + self.assertIsInstance(float(0.5).__ceil__(), int) + self.assertEqual(float(0.5).__ceil__(), 1) + self.assertEqual(float(1.0).__ceil__(), 1) + self.assertEqual(float(1.5).__ceil__(), 2) + self.assertEqual(float(-0.5).__ceil__(), 0) + self.assertEqual(float(-1.0).__ceil__(), -1) + self.assertEqual(float(-1.5).__ceil__(), -1) + self.assertEqual(float(1.23e167).__ceil__(), 1.23e167) + self.assertEqual(float(-1.23e167).__ceil__(), -1.23e167) + self.assertRaises(ValueError, float("nan").__ceil__) + self.assertRaises(OverflowError, float("inf").__ceil__) + self.assertRaises(OverflowError, float("-inf").__ceil__) + @support.requires_IEEE_754 def test_float_mod(self): # Check behaviour of % operator for IEEE 754 special cases. diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst b/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst new file mode 100644 index 00000000000000..c23c03e722646d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst @@ -0,0 +1,2 @@ +Implementation of missing floor and ceil methods to float object -- by +Batuhan Taskaya. diff --git a/Objects/clinic/floatobject.c.h b/Objects/clinic/floatobject.c.h index b684ba0ef27aaf..2ec8da230f4107 100644 --- a/Objects/clinic/floatobject.c.h +++ b/Objects/clinic/floatobject.c.h @@ -38,6 +38,42 @@ float___trunc__(PyObject *self, PyObject *Py_UNUSED(ignored)) return float___trunc___impl(self); } +PyDoc_STRVAR(float___floor____doc__, +"__floor__($self, /)\n" +"--\n" +"\n" +"Return the floor of x as an Integral."); + +#define FLOAT___FLOOR___METHODDEF \ + {"__floor__", (PyCFunction)float___floor__, METH_NOARGS, float___floor____doc__}, + +static PyObject * +float___floor___impl(PyObject *self); + +static PyObject * +float___floor__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return float___floor___impl(self); +} + +PyDoc_STRVAR(float___ceil____doc__, +"__ceil__($self, /)\n" +"--\n" +"\n" +"Return the ceiling of x as an Integral."); + +#define FLOAT___CEIL___METHODDEF \ + {"__ceil__", (PyCFunction)float___ceil__, METH_NOARGS, float___ceil____doc__}, + +static PyObject * +float___ceil___impl(PyObject *self); + +static PyObject * +float___ceil__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return float___ceil___impl(self); +} + PyDoc_STRVAR(float___round____doc__, "__round__($self, ndigits=None, /)\n" "--\n" @@ -351,4 +387,4 @@ float___format__(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=1676433b9f04fbc9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=398531a9a1a2c29e input=a9049054013a1b77]*/ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 8c08866d737253..bec4d35fc629be 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -923,6 +923,34 @@ float___trunc___impl(PyObject *self) return PyLong_FromDouble(wholepart); } +/*[clinic input] +float.__floor__ + +Return the floor as an Integral. +[clinic start generated code]*/ + +static PyObject * +float___floor___impl(PyObject *self) +/*[clinic end generated code: output=e0551dbaea8c01d1 input=38c8fb1dd0b579b4]*/ +{ + double x = PyFloat_AsDouble(self); + return PyLong_FromDouble(floor(x)); +} + +/*[clinic input] +float.__ceil__ + +Return the ceiling as an Integral. +[clinic start generated code]*/ + +static PyObject * +float___ceil___impl(PyObject *self) +/*[clinic end generated code: output=a2fd8858f73736f9 input=e3d4c94c2b8c8675]*/ +{ + double x = PyFloat_AsDouble(self); + return PyLong_FromDouble(ceil(x)); +} + /* double_round: rounds a finite double to the closest multiple of 10**-ndigits; here ndigits is within reasonable bounds (typically, -308 <= ndigits <= 323). Returns a Python float, or sets a Python error and @@ -1847,6 +1875,8 @@ float___format___impl(PyObject *self, PyObject *format_spec) static PyMethodDef float_methods[] = { FLOAT_CONJUGATE_METHODDEF FLOAT___TRUNC___METHODDEF + FLOAT___FLOOR___METHODDEF + FLOAT___CEIL___METHODDEF FLOAT___ROUND___METHODDEF FLOAT_AS_INTEGER_RATIO_METHODDEF FLOAT_FROMHEX_METHODDEF From e1ac18c44e005e66e0c1c8505c8dd2b9d337ceae Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 30 Oct 2019 18:25:43 +0300 Subject: [PATCH 2/3] update generated files --- Objects/clinic/floatobject.c.h | 6 +++--- Objects/floatobject.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Objects/clinic/floatobject.c.h b/Objects/clinic/floatobject.c.h index 2ec8da230f4107..b7554832b5a8a2 100644 --- a/Objects/clinic/floatobject.c.h +++ b/Objects/clinic/floatobject.c.h @@ -42,7 +42,7 @@ PyDoc_STRVAR(float___floor____doc__, "__floor__($self, /)\n" "--\n" "\n" -"Return the floor of x as an Integral."); +"Return the floor as an Integral."); #define FLOAT___FLOOR___METHODDEF \ {"__floor__", (PyCFunction)float___floor__, METH_NOARGS, float___floor____doc__}, @@ -60,7 +60,7 @@ PyDoc_STRVAR(float___ceil____doc__, "__ceil__($self, /)\n" "--\n" "\n" -"Return the ceiling of x as an Integral."); +"Return the ceiling as an Integral."); #define FLOAT___CEIL___METHODDEF \ {"__ceil__", (PyCFunction)float___ceil__, METH_NOARGS, float___ceil____doc__}, @@ -387,4 +387,4 @@ float___format__(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=398531a9a1a2c29e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=25fbbe253f44e2df input=a9049054013a1b77]*/ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index bec4d35fc629be..2145eeaaae1a29 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -931,7 +931,7 @@ Return the floor as an Integral. static PyObject * float___floor___impl(PyObject *self) -/*[clinic end generated code: output=e0551dbaea8c01d1 input=38c8fb1dd0b579b4]*/ +/*[clinic end generated code: output=e0551dbaea8c01d1 input=77bb13eb12e268df]*/ { double x = PyFloat_AsDouble(self); return PyLong_FromDouble(floor(x)); @@ -945,7 +945,7 @@ Return the ceiling as an Integral. static PyObject * float___ceil___impl(PyObject *self) -/*[clinic end generated code: output=a2fd8858f73736f9 input=e3d4c94c2b8c8675]*/ +/*[clinic end generated code: output=a2fd8858f73736f9 input=79e41ae94aa0a516]*/ { double x = PyFloat_AsDouble(self); return PyLong_FromDouble(ceil(x)); From 40db4db4ef5fa6d2e775d8d3846327f56c89b13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?= <47358913+isidentical@users.noreply.github.com> Date: Thu, 31 Oct 2019 15:21:57 +0300 Subject: [PATCH 3/3] use PyFloat_AS_DOUBLE for getting direct value without checking --- .../2019-10-29-17-11-15.bpo-38629.3qinhF.rst | 3 +-- Objects/floatobject.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst b/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst index c23c03e722646d..dadafcd898af53 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2019-10-29-17-11-15.bpo-38629.3qinhF.rst @@ -1,2 +1 @@ -Implementation of missing floor and ceil methods to float object -- by -Batuhan Taskaya. +Added ``__floor__`` and ``__ceil__`` methods to float object. Patch by Batuhan Taşkaya. diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 2145eeaaae1a29..ab265814a0eef6 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -933,7 +933,7 @@ static PyObject * float___floor___impl(PyObject *self) /*[clinic end generated code: output=e0551dbaea8c01d1 input=77bb13eb12e268df]*/ { - double x = PyFloat_AsDouble(self); + double x = PyFloat_AS_DOUBLE(self); return PyLong_FromDouble(floor(x)); } @@ -947,7 +947,7 @@ static PyObject * float___ceil___impl(PyObject *self) /*[clinic end generated code: output=a2fd8858f73736f9 input=79e41ae94aa0a516]*/ { - double x = PyFloat_AsDouble(self); + double x = PyFloat_AS_DOUBLE(self); return PyLong_FromDouble(ceil(x)); }