[Python-checkins] bpo-39434: Improve float __floordiv__ performance and error message (GH-18147)

Dong-hee Na webhook-mailer at python.org
Thu Jan 30 08:23:45 EST 2020


https://github.com/python/cpython/commit/8d49f7ceb4f961770ae61fe6a4033c4e61cc3288
commit: 8d49f7ceb4f961770ae61fe6a4033c4e61cc3288
branch: master
author: Dong-hee Na <donghee.na92 at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-01-30T13:23:15Z
summary:

bpo-39434: Improve float __floordiv__ performance and error message (GH-18147)

files:
A Misc/NEWS.d/next/Core and Builtins/2020-01-24-01-07-04.bpo-39434.S5ehj9.rst
M Objects/floatobject.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-01-24-01-07-04.bpo-39434.S5ehj9.rst b/Misc/NEWS.d/next/Core and Builtins/2020-01-24-01-07-04.bpo-39434.S5ehj9.rst
new file mode 100644
index 0000000000000..e5a413323ac43
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-01-24-01-07-04.bpo-39434.S5ehj9.rst	
@@ -0,0 +1,3 @@
+:term:`floor division` of float operation now has a better performance. Also
+the message of :exc:`ZeroDivisionError` for this operation is updated.
+Patch by Dong-hee Na.
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d67f17abb5c27..89f60b65cd55c 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -611,29 +611,22 @@ float_rem(PyObject *v, PyObject *w)
     return PyFloat_FromDouble(mod);
 }
 
-static PyObject *
-float_divmod(PyObject *v, PyObject *w)
+static void
+_float_div_mod(double vx, double wx, double *floordiv, double *mod)
 {
-    double vx, wx;
-    double div, mod, floordiv;
-    CONVERT_TO_DOUBLE(v, vx);
-    CONVERT_TO_DOUBLE(w, wx);
-    if (wx == 0.0) {
-        PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
-        return NULL;
-    }
-    mod = fmod(vx, wx);
+    double div;
+    *mod = fmod(vx, wx);
     /* fmod is typically exact, so vx-mod is *mathematically* an
        exact multiple of wx.  But this is fp arithmetic, and fp
        vx - mod is an approximation; the result is that div may
        not be an exact integral value after the division, although
        it will always be very close to one.
     */
-    div = (vx - mod) / wx;
-    if (mod) {
+    div = (vx - *mod) / wx;
+    if (*mod) {
         /* ensure the remainder has the same sign as the denominator */
-        if ((wx < 0) != (mod < 0)) {
-            mod += wx;
+        if ((wx < 0) != (*mod < 0)) {
+            *mod += wx;
             div -= 1.0;
         }
     }
@@ -641,34 +634,49 @@ float_divmod(PyObject *v, PyObject *w)
         /* the remainder is zero, and in the presence of signed zeroes
            fmod returns different results across platforms; ensure
            it has the same sign as the denominator. */
-        mod = copysign(0.0, wx);
+        *mod = copysign(0.0, wx);
     }
     /* snap quotient to nearest integral value */
     if (div) {
-        floordiv = floor(div);
-        if (div - floordiv > 0.5)
-            floordiv += 1.0;
+        *floordiv = floor(div);
+        if (div - *floordiv > 0.5) {
+            *floordiv += 1.0;
+        }       
     }
     else {
         /* div is zero - get the same sign as the true quotient */
-        floordiv = copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */
+        *floordiv = copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */
     }
-    return Py_BuildValue("(dd)", floordiv, mod);
+}
+
+static PyObject *
+float_divmod(PyObject *v, PyObject *w)
+{
+     double vx, wx;
+     double mod, floordiv;
+     CONVERT_TO_DOUBLE(v, vx);
+     CONVERT_TO_DOUBLE(w, wx);
+     if (wx == 0.0) {
+         PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
+         return NULL;
+     }
+     _float_div_mod(vx, wx, &floordiv, &mod);
+     return Py_BuildValue("(dd)", floordiv, mod);
 }
 
 static PyObject *
 float_floor_div(PyObject *v, PyObject *w)
 {
-    PyObject *t, *r;
-
-    t = float_divmod(v, w);
-    if (t == NULL || t == Py_NotImplemented)
-        return t;
-    assert(PyTuple_CheckExact(t));
-    r = PyTuple_GET_ITEM(t, 0);
-    Py_INCREF(r);
-    Py_DECREF(t);
-    return r;
+    double vx, wx;
+    double mod, floordiv;
+    CONVERT_TO_DOUBLE(v, vx);
+    CONVERT_TO_DOUBLE(w, wx);
+    if (wx == 0.0) {
+        PyErr_SetString(PyExc_ZeroDivisionError, "float floor division by zero");
+        return NULL;
+    }
+    _float_div_mod(vx, wx, &floordiv, &mod);
+    return PyFloat_FromDouble(floordiv);
 }
 
 /* determine whether x is an odd integer or not;  assumes that



More information about the Python-checkins mailing list