diff options
author | Dong-hee Na <donghee.na92@gmail.com> | 2020-01-30 13:23:15 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-30 13:23:15 (GMT) |
commit | 8d49f7ceb4f961770ae61fe6a4033c4e61cc3288 (patch) | |
tree | bf3e0f674c1d714ebe98486bad2a46ecaeeffe0e /Objects/floatobject.c | |
parent | 2a4903fcce54c25807d362dbbbcfb32d0b494f9f (diff) | |
download | cpython-8d49f7ceb4f961770ae61fe6a4033c4e61cc3288.zip cpython-8d49f7ceb4f961770ae61fe6a4033c4e61cc3288.tar.gz cpython-8d49f7ceb4f961770ae61fe6a4033c4e61cc3288.tar.bz2 |
bpo-39434: Improve float __floordiv__ performance and error message (GH-18147)
Diffstat (limited to 'Objects/floatobject.c')
-rw-r--r-- | Objects/floatobject.c | 70 |
1 files changed, 39 insertions, 31 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c index d67f17a..89f60b6 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 |