Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9263e78

Browse files
committed
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).
1 parent 8e40759 commit 9263e78

1 file changed

Lines changed: 19 additions & 7 deletions

File tree

Objects/floatobject.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ float_rem(v, w)
359359
PyFloatObject *w;
360360
{
361361
double vx, wx;
362-
double /* div, */ mod;
362+
double mod;
363363
wx = w->ob_fval;
364364
if (wx == 0.0) {
365365
PyErr_SetString(PyExc_ZeroDivisionError, "float modulo");
@@ -368,10 +368,10 @@ float_rem(v, w)
368368
PyFPE_START_PROTECT("modulo", return 0)
369369
vx = v->ob_fval;
370370
mod = fmod(vx, wx);
371-
/* div = (vx - mod) / wx; */
372-
if (wx*mod < 0) {
371+
/* note: checking mod*wx < 0 is incorrect -- underflows to
372+
0 if wx < sqrt(smallest nonzero double) */
373+
if (mod && ((wx < 0) != (mod < 0))) {
373374
mod += wx;
374-
/* div -= 1.0; */
375375
}
376376
PyFPE_END_PROTECT(mod)
377377
return PyFloat_FromDouble(mod);
@@ -383,7 +383,7 @@ float_divmod(v, w)
383383
PyFloatObject *w;
384384
{
385385
double vx, wx;
386-
double div, mod;
386+
double div, mod, floordiv;
387387
wx = w->ob_fval;
388388
if (wx == 0.0) {
389389
PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
@@ -392,13 +392,25 @@ float_divmod(v, w)
392392
PyFPE_START_PROTECT("divmod", return 0)
393393
vx = v->ob_fval;
394394
mod = fmod(vx, wx);
395+
/* fmod is typically exact, so vx-mod is *mathemtically* an
396+
exact multiple of wx. But this is fp arithmetic, and fp
397+
vx - mod is an approximation; the result is that div may
398+
not be an exact integral value after the division, although
399+
it will always be very close to one.
400+
*/
395401
div = (vx - mod) / wx;
396-
if (wx*mod < 0) {
402+
/* note: checking mod*wx < 0 is incorrect -- underflows to
403+
0 if wx < sqrt(smallest nonzero double) */
404+
if (mod && ((wx < 0) != (mod < 0))) {
397405
mod += wx;
398406
div -= 1.0;
399407
}
408+
/* snap quotient to nearest integral value */
409+
floordiv = floor(div);
410+
if (div - floordiv > 0.5)
411+
floordiv += 1.0;
400412
PyFPE_END_PROTECT(div)
401-
return Py_BuildValue("(dd)", div, mod);
413+
return Py_BuildValue("(dd)", floordiv, mod);
402414
}
403415

404416
static double powu(x, n)

0 commit comments

Comments
 (0)