diff options
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/umath/loops_arithmetic.dispatch.c.src | 49 | ||||
| -rw-r--r-- | numpy/core/tests/test_regression.py | 2 | ||||
| -rw-r--r-- | numpy/core/tests/test_umath.py | 30 |
3 files changed, 52 insertions, 29 deletions
diff --git a/numpy/core/src/umath/loops_arithmetic.dispatch.c.src b/numpy/core/src/umath/loops_arithmetic.dispatch.c.src index 16a9eac2e..15f438cbe 100644 --- a/numpy/core/src/umath/loops_arithmetic.dispatch.c.src +++ b/numpy/core/src/umath/loops_arithmetic.dispatch.c.src @@ -51,13 +51,14 @@ simd_divide_by_scalar_contig_@sfx@(char **args, npy_intp len) const npyv_@sfx@x3 divisor = npyv_divisor_@sfx@(scalar); if (scalar == -1) { - npyv_b@len@ noverflow = npyv_cvt_b@len@_@sfx@(npyv_setall_@sfx@(-1)); - npyv_@sfx@ vzero = npyv_zero_@sfx@(); + npyv_b@len@ noverflow = npyv_cvt_b@len@_@sfx@(npyv_setall_@sfx@(-1)); + const npyv_@sfx@ vzero = npyv_zero_@sfx@(); + const npyv_@sfx@ vmin = npyv_setall_@sfx@(NPY_MIN_INT@len@); for (; len >= vstep; len -= vstep, src += vstep, dst += vstep) { npyv_@sfx@ a = npyv_load_@sfx@(src); npyv_b@len@ gt_min = npyv_cmpgt_@sfx@(a, npyv_setall_@sfx@(NPY_MIN_INT@len@)); noverflow = npyv_and_b@len@(noverflow, gt_min); - npyv_@sfx@ neg = npyv_ifsub_@sfx@(gt_min, vzero, a, vzero); + npyv_@sfx@ neg = npyv_ifsub_@sfx@(gt_min, vzero, a, vmin); npyv_store_@sfx@(dst, neg); } @@ -66,13 +67,13 @@ simd_divide_by_scalar_contig_@sfx@(char **args, npy_intp len) npyv_lanetype_@sfx@ a = *src; if (a == NPY_MIN_INT@len@) { raise_err = 1; - *dst = 0; + *dst = NPY_MIN_INT@len@; } else { *dst = -a; } } if (raise_err) { - npy_set_floatstatus_divbyzero(); + npy_set_floatstatus_overflow(); } } else { for (; len >= vstep; len -= vstep, src += vstep, dst += vstep) { @@ -253,7 +254,8 @@ vsx4_simd_divide_contig_@sfx@(char **args, npy_intp len) const npyv_@sfx@ vneg_one = npyv_setall_@sfx@(-1); const npyv_@sfx@ vzero = npyv_zero_@sfx@(); const npyv_@sfx@ vmin = npyv_setall_@sfx@(NPY_MIN_INT@len@); - npyv_b@len@ warn = npyv_cvt_b@len@_@sfx@(npyv_zero_@sfx@()); + npyv_b@len@ warn_zero = npyv_cvt_b@len@_@sfx@(npyv_zero_@sfx@()); + npyv_b@len@ warn_overflow = npyv_cvt_b@len@_@sfx@(npyv_zero_@sfx@()); const int vstep = npyv_nlanes_@sfx@; for (; len >= vstep; len -= vstep, src1 += vstep, src2 += vstep, @@ -267,10 +269,8 @@ vsx4_simd_divide_contig_@sfx@(char **args, npy_intp len) npyv_b@len@ amin = npyv_cmpeq_@sfx@(a, vmin); npyv_b@len@ bneg_one = npyv_cmpeq_@sfx@(b, vneg_one); npyv_b@len@ overflow = npyv_and_@sfx@(bneg_one, amin); - npyv_b@len@ error = npyv_or_@sfx@(bzero, overflow); - // in case of overflow or b = 0, 'cvtozero' forces quo/rem to be 0 - npyv_@sfx@ cvtozero = npyv_select_@sfx@(error, vzero, vneg_one); - warn = npyv_or_@sfx@(error, warn); + warn_zero = npyv_or_@sfx@(bzero, warn_zero); + warn_overflow = npyv_or_@sfx@(overflow, warn_overflow); // handle mixed case the way Python does // ((a > 0) == (b > 0) || rem == 0) npyv_b@len@ a_gt_zero = npyv_cmpgt_@sfx@(a, vzero); @@ -280,21 +280,30 @@ vsx4_simd_divide_contig_@sfx@(char **args, npy_intp len) npyv_b@len@ or = npyv_or_@sfx@(ab_eq_cond, rem_zero); npyv_@sfx@ to_sub = npyv_select_@sfx@(or, vzero, vneg_one); quo = npyv_add_@sfx@(quo, to_sub); - npyv_store_@sfx@(dst1, npyv_and_@sfx@(cvtozero, quo)); + // Divide by zero + quo = npyv_select_@sfx@(bzero, vzero, quo); + // Overflow + quo = npyv_select_@sfx@(overflow, vmin, quo); + npyv_store_@sfx@(dst1, quo); } - if (!vec_all_eq(warn, vzero)) { + if (!vec_all_eq(warn_zero, vzero)) { npy_set_floatstatus_divbyzero(); } + if (!vec_all_eq(warn_overflow, vzero)) { + npy_set_floatstatus_overflow(); + } for (; len > 0; --len, ++src1, ++src2, ++dst1) { const npyv_lanetype_@sfx@ a = *src1; const npyv_lanetype_@sfx@ b = *src2; - if (b == 0 || (a == NPY_MIN_INT@len@ && b == -1)) { + if (NPY_UNLIKELY(b == 0)) { npy_set_floatstatus_divbyzero(); *dst1 = 0; - } - else { + } else if (NPY_UNLIKELY((a == NPY_MIN_INT@len@) && (b == -1))) { + npy_set_floatstatus_overflow(); + *dst1 = NPY_MIN_INT@len@; + } else { *dst1 = a / b; if (((a > 0) != (b > 0)) && ((*dst1 * b) != a)) { *dst1 -= 1; @@ -340,8 +349,14 @@ NPY_FINLINE @type@ floor_div_@TYPE@(const @type@ n, const @type@ d) * (i.e. a different approach than npy_set_floatstatus_divbyzero()). */ if (NPY_UNLIKELY(d == 0 || (n == NPY_MIN_@TYPE@ && d == -1))) { - npy_set_floatstatus_divbyzero(); - return 0; + if (d == 0) { + npy_set_floatstatus_divbyzero(); + return 0; + } + else { + npy_set_floatstatus_overflow(); + return NPY_MIN_@TYPE@; + } } @type@ r = n / d; // Negative quotients needs to be rounded down diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 98e0df9b8..4388023dc 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -1496,7 +1496,7 @@ class TestRegression: min = np.array([np.iinfo(t).min]) min //= -1 - with np.errstate(divide="ignore"): + with np.errstate(over="ignore"): for t in (np.int8, np.int16, np.int32, np.int64, int): test_type(t) diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 7b6e2ee92..a696fceb8 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -327,7 +327,9 @@ class TestDivision: a_lst, b_lst = a.tolist(), b.tolist() c_div = lambda n, d: ( - 0 if d == 0 or (n and n == fo.min and d == -1) else n//d + 0 if d == 0 else ( + fo.min if (n and n == fo.min and d == -1) else n//d + ) ) with np.errstate(divide='ignore'): ac = a.copy() @@ -342,7 +344,7 @@ class TestDivision: for divisor in divisors: ac = a.copy() - with np.errstate(divide='ignore'): + with np.errstate(divide='ignore', over='ignore'): div_a = a // divisor ac //= divisor div_lst = [c_div(i, divisor) for i in a_lst] @@ -350,21 +352,25 @@ class TestDivision: assert all(div_a == div_lst), msg assert all(ac == div_lst), msg_eq - with np.errstate(divide='raise'): - if 0 in b or (fo.min and -1 in b and fo.min in a): + with np.errstate(divide='raise', over='raise'): + if 0 in b: # Verify overflow case - with pytest.raises(FloatingPointError): + with pytest.raises(FloatingPointError, + match="divide by zero encountered in floor_divide"): a // b else: a // b if fo.min and fo.min in a: - with pytest.raises(FloatingPointError): + with pytest.raises(FloatingPointError, + match='overflow encountered in floor_divide'): a // -1 elif fo.min: a // -1 - with pytest.raises(FloatingPointError): + with pytest.raises(FloatingPointError, + match="divide by zero encountered in floor_divide"): a // 0 - with pytest.raises(FloatingPointError): + with pytest.raises(FloatingPointError, + match="divide by zero encountered in floor_divide"): ac = a.copy() ac //= 0 @@ -392,11 +398,13 @@ class TestDivision: msg = "Reduce floor integer division check" assert div_a == div_lst, msg - with np.errstate(divide='raise'): - with pytest.raises(FloatingPointError): + with np.errstate(divide='raise', over='raise'): + with pytest.raises(FloatingPointError, + match="divide by zero encountered in reduce"): np.floor_divide.reduce(np.arange(-100, 100, dtype=dtype)) if fo.min: - with pytest.raises(FloatingPointError): + with pytest.raises(FloatingPointError, + match='overflow encountered in reduce'): np.floor_divide.reduce( np.array([fo.min, 1, -1], dtype=dtype) ) |
