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

Skip to content

Commit 34c2369

Browse files
committed
BUG: Make divmod behave better under roundoff error.
This is apropos #6127. The fix is to make the functions floor_division and remainder consistent, i.e., b * floor_division(a, b) + remainder(a, b) == a Previous to this fix remainder was computed a the C level using the '%' operator, and the result was not always consistent with the floor function. The current approach is to compute the remainder using b * (a/b - floor(a/b)) which is both consistent with the Python '%' operator and numerically consistent with floor_division implemented using the floor function. Closes #6127.
1 parent 7141f40 commit 34c2369

File tree

2 files changed

+11
-23
lines changed

2 files changed

+11
-23
lines changed

numpy/core/src/umath/loops.c.src

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,13 +1688,8 @@ NPY_NO_EXPORT void
16881688
BINARY_LOOP {
16891689
const @type@ in1 = *(@type@ *)ip1;
16901690
const @type@ in2 = *(@type@ *)ip2;
1691-
const @type@ res = npy_fmod@c@(in1,in2);
1692-
if (res && ((in2 < 0) != (res < 0))) {
1693-
*((@type@ *)op1) = res + in2;
1694-
}
1695-
else {
1696-
*((@type@ *)op1) = res;
1697-
}
1691+
const @type@ div = in1/in2;
1692+
*((@type@ *)op1) = in2*(div - npy_floor@c@(div));
16981693
}
16991694
}
17001695

numpy/core/src/umath/scalarmath.c.src

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,10 @@ static void
272272
static @type@ (*_basic_@name@_floor)(@type@);
273273
static @type@ (*_basic_@name@_sqrt)(@type@);
274274
static @type@ (*_basic_@name@_fmod)(@type@, @type@);
275-
#define @name@_ctype_add(a, b, outp) *(outp) = a + b
276-
#define @name@_ctype_subtract(a, b, outp) *(outp) = a - b
277-
#define @name@_ctype_multiply(a, b, outp) *(outp) = a * b
278-
#define @name@_ctype_divide(a, b, outp) *(outp) = a / b
275+
#define @name@_ctype_add(a, b, outp) *(outp) = (a) + (b)
276+
#define @name@_ctype_subtract(a, b, outp) *(outp) = (a) - (b)
277+
#define @name@_ctype_multiply(a, b, outp) *(outp) = (a) * (b)
278+
#define @name@_ctype_divide(a, b, outp) *(outp) = (a) / (b)
279279
#define @name@_ctype_true_divide @name@_ctype_divide
280280
#define @name@_ctype_floor_divide(a, b, outp) \
281281
*(outp) = _basic_@name@_floor((a) / (b))
@@ -343,23 +343,16 @@ static npy_half (*_basic_half_fmod)(npy_half, npy_half);
343343
*/
344344
static void
345345
@name@_ctype_remainder(@type@ a, @type@ b, @type@ *out) {
346-
@type@ mod;
347-
mod = _basic_@name@_fmod(a, b);
348-
if (mod && (((b < 0) != (mod < 0)))) {
349-
mod += b;
350-
}
351-
*out = mod;
346+
@type@ tmp = a/b;
347+
*out = b * (tmp - _basic_@name@_floor(tmp));
352348
}
353349
/**end repeat**/
354350

355351
static void
356352
half_ctype_remainder(npy_half a, npy_half b, npy_half *out) {
357-
float mod, fa = npy_half_to_float(a), fb = npy_half_to_float(b);
358-
mod = _basic_float_fmod(fa, fb);
359-
if (mod && (((fb < 0) != (mod < 0)))) {
360-
mod += fb;
361-
}
362-
*out = npy_float_to_half(mod);
353+
float tmp, fa = npy_half_to_float(a), fb = npy_half_to_float(b);
354+
float_ctype_remainder(fa, fb, &tmp);
355+
*out = npy_float_to_half(tmp);
363356
}
364357

365358

0 commit comments

Comments
 (0)