summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1999-05-06 14:26:34 (GMT)
committerGuido van Rossum <guido@python.org>1999-05-06 14:26:34 (GMT)
commit9263e78ff22a5aaa0c2b460df966e048dd28f90d (patch)
treedcac24796e593296ccf22f02e26ef81fc70b1707 /Objects
parent8e40759d5ae2c879759fe7c3e35aa107f967824b (diff)
downloadcpython-9263e78ff22a5aaa0c2b460df966e048dd28f90d.zip
cpython-9263e78ff22a5aaa0c2b460df966e048dd28f90d.tar.gz
cpython-9263e78ff22a5aaa0c2b460df966e048dd28f90d.tar.bz2
Tim Peters writes:
1. Fixes float divmod so that the quotient it returns is always an integral value. 2. Fixes float % and float divmod so that the remainder always gets the right sign (the current code uses a "are the signs different?" test that doesn't work half the time <wink> when the product of the divisor and the remainder underflows to 0).
Diffstat (limited to 'Objects')
-rw-r--r--Objects/floatobject.c26
1 files changed, 19 insertions, 7 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 120b561..ba37309 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -359,7 +359,7 @@ float_rem(v, w)
PyFloatObject *w;
{
double vx, wx;
- double /* div, */ mod;
+ double mod;
wx = w->ob_fval;
if (wx == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError, "float modulo");
@@ -368,10 +368,10 @@ float_rem(v, w)
PyFPE_START_PROTECT("modulo", return 0)
vx = v->ob_fval;
mod = fmod(vx, wx);
- /* div = (vx - mod) / wx; */
- if (wx*mod < 0) {
+ /* note: checking mod*wx < 0 is incorrect -- underflows to
+ 0 if wx < sqrt(smallest nonzero double) */
+ if (mod && ((wx < 0) != (mod < 0))) {
mod += wx;
- /* div -= 1.0; */
}
PyFPE_END_PROTECT(mod)
return PyFloat_FromDouble(mod);
@@ -383,7 +383,7 @@ float_divmod(v, w)
PyFloatObject *w;
{
double vx, wx;
- double div, mod;
+ double div, mod, floordiv;
wx = w->ob_fval;
if (wx == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
@@ -392,13 +392,25 @@ float_divmod(v, w)
PyFPE_START_PROTECT("divmod", return 0)
vx = v->ob_fval;
mod = fmod(vx, wx);
+ /* fmod is typically exact, so vx-mod is *mathemtically* 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 (wx*mod < 0) {
+ /* note: checking mod*wx < 0 is incorrect -- underflows to
+ 0 if wx < sqrt(smallest nonzero double) */
+ if (mod && ((wx < 0) != (mod < 0))) {
mod += wx;
div -= 1.0;
}
+ /* snap quotient to nearest integral value */
+ floordiv = floor(div);
+ if (div - floordiv > 0.5)
+ floordiv += 1.0;
PyFPE_END_PROTECT(div)
- return Py_BuildValue("(dd)", div, mod);
+ return Py_BuildValue("(dd)", floordiv, mod);
}
static double powu(x, n)