From 671a22472babfbea1bdbdb203284afe370596382 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 23 Dec 2017 12:32:48 +0900 Subject: [PATCH 01/15] BUG: Fix strange behavior of infinite step size in arange --- numpy/core/src/multiarray/ctors.c | 50 ++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index c9b3125aefd6..51636cdfc579 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -2942,11 +2942,25 @@ PyArray_Arange(double start, double stop, double step, int type_num) PyArray_ArrFuncs *funcs; PyObject *obj; int ret; + double delta, tmp_len; NPY_BEGIN_THREADS_DEF; - if (_safe_ceil_to_intp((stop - start)/step, &length)) { - PyErr_SetString(PyExc_OverflowError, - "arange: overflow while computing length"); + delta = stop - start; + tmp_len = delta/step; + + if (tmp_len == 0.0 && delta != 0.0) { + if (signbit(tmp_len)) { + length = -1.0; + } + else { + length = 1.0; + } + } + else { + if (_safe_ceil_to_intp(tmp_len, &length)) { + PyErr_SetString(PyExc_OverflowError, + "arange: overflow while computing length"); + } } if (length <= 0) { @@ -3009,7 +3023,8 @@ PyArray_Arange(double start, double stop, double step, int type_num) static npy_intp _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, int cmplx) { - npy_intp len, tmp; + npy_intp len, tmp, next_is_nonzero, val_is_zero; + PyObject *zero = PyInt_FromLong(0); PyObject *val; double value; @@ -3023,12 +3038,19 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i } return -1; } + + next_is_nonzero = PyObject_RichCompareBool(*next, zero, Py_NE); val = PyNumber_TrueDivide(*next, step); Py_DECREF(*next); *next = NULL; + if (!val) { return -1; } + + val_is_zero = PyObject_RichCompareBool(val, zero, Py_EQ); + Py_DECREF(zero); + if (cmplx && PyComplex_Check(val)) { value = PyComplex_RealAsDouble(val); if (error_converting(value)) { @@ -3059,12 +3081,24 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i if (error_converting(value)) { return -1; } - if (_safe_ceil_to_intp(value, &len)) { - PyErr_SetString(PyExc_OverflowError, - "arange: overflow while computing length"); - return -1; + + if (val_is_zero && next_is_nonzero) { + if (signbit(value)) { + len = -1.0; + } + else { + len = 1.0; + } + } + else { + if (_safe_ceil_to_intp(value, &len)) { + PyErr_SetString(PyExc_OverflowError, + "arange: overflow while computing length"); + return -1; + } } } + if (len > 0) { *next = PyNumber_Add(start, step); if (!*next) { From 825c6816bad1c95ea6da9daceb3551eeba27d9c0 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 23 Dec 2017 13:02:59 +0900 Subject: [PATCH 02/15] TST: Add tests for np.arange with inf step --- numpy/core/tests/test_regression.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 84469d03ba08..09e484b9df78 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -234,6 +234,23 @@ def test_arange_endian(self): x = np.arange(10, dtype='>f8') assert_array_equal(ref, x) + def test_arange_inf_step(self): + ref = np.arange(0, 1, 10) + x = np.arange(0, 1, np.inf) + assert_array_equal(ref, x) + + ref = np.arange(0, 1, -10) + x = np.arange(0, 1, -np.inf) + assert_array_equal(ref, x) + + ref = np.arange(0, -1, -10) + x = np.arange(0, -1, -np.inf) + assert_array_equal(ref, x) + + ref = np.arange(0, -1, 10) + x = np.arange(0, -1, np.inf) + assert_array_equal(ref, x) + def test_argmax(self): # Ticket #119 a = np.random.normal(0, 1, (4, 5, 6, 7, 8)) From 2607ad73ecd7c4c1fbeb53af5c817cc42d67dcd1 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 23 Dec 2017 13:40:24 +0900 Subject: [PATCH 03/15] Fix build error on Windows --- numpy/core/src/multiarray/ctors.c | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 34b5512715d5..93ecfe5e9fc0 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -28,6 +28,7 @@ #include "templ_common.h" /* for npy_mul_with_overflow_intp */ #include "alloc.h" #include +#include #include "get_attr_string.h" From 123da274e4cda8d818d004ea545b0f021d39714f Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 23 Dec 2017 13:40:53 +0900 Subject: [PATCH 04/15] Fix unnecessary calculation --- numpy/core/src/multiarray/ctors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 93ecfe5e9fc0..a94d5442ca4b 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -2984,7 +2984,7 @@ PyArray_Arange(double start, double stop, double step, int type_num) } } else { - length = _arange_safe_ceil_to_intp((stop - start)/step); + length = _arange_safe_ceil_to_intp(tmp_len); if (error_converting(length)) { return NULL; } From e2cc3e63b98e710eb3d13ae0e9eeba80baec7090 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 23 Dec 2017 15:25:16 +0900 Subject: [PATCH 05/15] Use npy_signbit --- numpy/core/src/multiarray/ctors.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index a94d5442ca4b..da1a017433bf 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -28,7 +28,6 @@ #include "templ_common.h" /* for npy_mul_with_overflow_intp */ #include "alloc.h" #include -#include #include "get_attr_string.h" @@ -2976,7 +2975,7 @@ PyArray_Arange(double start, double stop, double step, int type_num) tmp_len = delta/step; if (tmp_len == 0.0 && delta != 0.0) { - if (signbit(tmp_len)) { + if (npy_signbit(tmp_len)) { length = -1.0; } else { @@ -3108,7 +3107,7 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i } if (val_is_zero && next_is_nonzero) { - if (signbit(value)) { + if (npy_signbit(value)) { len = -1.0; } else { From d4d27589dc39e1309a262140363f1cf612e1dfe3 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sun, 24 Dec 2017 22:22:27 +0900 Subject: [PATCH 06/15] Add commnt --- numpy/core/src/multiarray/ctors.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index da1a017433bf..cdcf826b2e26 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -2974,6 +2974,7 @@ PyArray_Arange(double start, double stop, double step, int type_num) delta = stop - start; tmp_len = delta/step; + /* Underflow and divide-by-inf check */ if (tmp_len == 0.0 && delta != 0.0) { if (npy_signbit(tmp_len)) { length = -1.0; @@ -3106,6 +3107,7 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i return -1; } + /* Underflow and divide-by-inf check */ if (val_is_zero && next_is_nonzero) { if (npy_signbit(value)) { len = -1.0; From 2827c66e69fe2deaea403a06eee1ed9a117514e7 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Thu, 28 Dec 2017 01:20:10 +0900 Subject: [PATCH 07/15] Use int as bool, not intp --- numpy/core/src/multiarray/ctors.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index cdcf826b2e26..ce4714b5e57c 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3050,9 +3050,10 @@ PyArray_Arange(double start, double stop, double step, int type_num) static npy_intp _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, int cmplx) { - npy_intp len, tmp, next_is_nonzero, val_is_zero; + npy_intp len, tmp; PyObject *zero = PyInt_FromLong(0); PyObject *val; + int next_is_nonzero, val_is_zero; double value; *next = PyNumber_Subtract(stop, start); From 0b60753fb45f1dd75bdd4a2b3d867bcf71f0a228 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Thu, 28 Dec 2017 01:20:43 +0900 Subject: [PATCH 08/15] Dereference the leaked PyObject --- numpy/core/src/multiarray/ctors.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index ce4714b5e57c..eaad0acb00b5 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3058,6 +3058,8 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i *next = PyNumber_Subtract(stop, start); if (!(*next)) { + Py_DECREF(zero); + if (PyTuple_Check(stop)) { PyErr_Clear(); PyErr_SetString(PyExc_TypeError, @@ -3073,6 +3075,7 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i *next = NULL; if (!val) { + Py_DECREF(zero); return -1; } From 41cd4e123dd7fb754d1ff190b1c068bd81b715f8 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Thu, 28 Dec 2017 09:30:23 +0900 Subject: [PATCH 09/15] Add zero PyObject pointer null-check --- numpy/core/src/multiarray/ctors.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index eaad0acb00b5..75b99931f369 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3051,11 +3051,15 @@ static npy_intp _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, int cmplx) { npy_intp len, tmp; - PyObject *zero = PyInt_FromLong(0); - PyObject *val; + PyObject *zero, *val; int next_is_nonzero, val_is_zero; double value; + zero = PyInt_FromLong(0); + if (!zero) { + return -1; + } + *next = PyNumber_Subtract(stop, start); if (!(*next)) { Py_DECREF(zero); From 12d020c217f1c9ed0e93ab1c38e96bf584e38dca Mon Sep 17 00:00:00 2001 From: Licht-T Date: Fri, 29 Dec 2017 16:05:57 +0900 Subject: [PATCH 10/15] Change the order of pointer initialization --- numpy/core/src/multiarray/ctors.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 75b99931f369..ca223b740fed 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3055,15 +3055,8 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i int next_is_nonzero, val_is_zero; double value; - zero = PyInt_FromLong(0); - if (!zero) { - return -1; - } - *next = PyNumber_Subtract(stop, start); if (!(*next)) { - Py_DECREF(zero); - if (PyTuple_Check(stop)) { PyErr_Clear(); PyErr_SetString(PyExc_TypeError, @@ -3073,6 +3066,13 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i return -1; } + zero = PyInt_FromLong(0); + if (!zero) { + Py_DECREF(*next); + *next = NULL; + return -1; + } + next_is_nonzero = PyObject_RichCompareBool(*next, zero, Py_NE); val = PyNumber_TrueDivide(*next, step); Py_DECREF(*next); From c5f589d57c192060adefd9c8b5f4333c45e2d321 Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 30 Dec 2017 01:05:10 +0900 Subject: [PATCH 11/15] TST: Add tests for np.arange with underflow cases --- numpy/core/tests/test_regression.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index ee18060d6618..ea08710d8477 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -241,6 +241,25 @@ def test_arange_inf_step(self): x = np.arange(0, -1, np.inf) assert_array_equal(ref, x) + def test_arange_underflow_stop_and_step(self): + finfo = np.finfo(np.float64) + + ref = np.arange(0, finfo.eps, 2 * finfo.eps) + x = np.arange(0, finfo.eps, finfo.max) + assert_array_equal(ref, x) + + ref = np.arange(0, finfo.eps, -2 * finfo.eps) + x = np.arange(0, finfo.eps, -finfo.max) + assert_array_equal(ref, x) + + ref = np.arange(0, -finfo.eps, -2 * finfo.eps) + x = np.arange(0, -finfo.eps, -finfo.max) + assert_array_equal(ref, x) + + ref = np.arange(0, -finfo.eps, 2 * finfo.eps) + x = np.arange(0, -finfo.eps, finfo.max) + assert_array_equal(ref, x) + def test_argmax(self): # Ticket #119 a = np.random.normal(0, 1, (4, 5, 6, 7, 8)) From 514c8eca9fdd0048ef395a9051812bb35416a48d Mon Sep 17 00:00:00 2001 From: Licht-T Date: Wed, 2 May 2018 19:30:54 +0900 Subject: [PATCH 12/15] Remove the assigning a double value to a integer variable --- numpy/core/src/multiarray/ctors.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index b284dde9c43d..e0c17bb2e118 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3008,10 +3008,10 @@ PyArray_Arange(double start, double stop, double step, int type_num) /* Underflow and divide-by-inf check */ if (tmp_len == 0.0 && delta != 0.0) { if (npy_signbit(tmp_len)) { - length = -1.0; + length = 0; } else { - length = 1.0; + length = 1; } } else { @@ -3149,10 +3149,10 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i /* Underflow and divide-by-inf check */ if (val_is_zero && next_is_nonzero) { if (npy_signbit(value)) { - len = -1.0; + len = 0; } else { - len = 1.0; + len = 1; } } else { From d68afb36dd37ca9d8ed8604830cf8e5c2b14a94d Mon Sep 17 00:00:00 2001 From: Licht-T Date: Sat, 5 May 2018 00:10:44 +0900 Subject: [PATCH 13/15] Add `PyObject_RichCompareBool` success check --- numpy/core/src/multiarray/ctors.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index e0c17bb2e118..c4445c813a2f 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3105,6 +3105,12 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i } next_is_nonzero = PyObject_RichCompareBool(*next, zero, Py_NE); + if (next_is_nonzero == -1) { + Py_DECREF(zero); + Py_DECREF(*next); + *next = NULL; + return -1; + } val = PyNumber_TrueDivide(*next, step); Py_DECREF(*next); *next = NULL; @@ -3116,6 +3122,10 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i val_is_zero = PyObject_RichCompareBool(val, zero, Py_EQ); Py_DECREF(zero); + if (val_is_zero == -1) { + Py_DECREF(val); + return -1; + } if (cmplx && PyComplex_Check(val)) { value = PyComplex_RealAsDouble(val); From 2740bc9e6a2a728614cab86daca47393e020d58b Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 30 May 2018 23:33:42 -0700 Subject: [PATCH 14/15] STY: Fix whitespace --- numpy/core/src/multiarray/ctors.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index c4445c813a2f..58a68c5d940a 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3106,10 +3106,10 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i next_is_nonzero = PyObject_RichCompareBool(*next, zero, Py_NE); if (next_is_nonzero == -1) { - Py_DECREF(zero); - Py_DECREF(*next); - *next = NULL; - return -1; + Py_DECREF(zero); + Py_DECREF(*next); + *next = NULL; + return -1; } val = PyNumber_TrueDivide(*next, step); Py_DECREF(*next); From 04a85b4559de69e99471c66f8138994cff36920a Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 30 May 2018 23:34:32 -0700 Subject: [PATCH 15/15] STY: Fix whitespace --- numpy/core/src/multiarray/ctors.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 58a68c5d940a..da017eb0dc31 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3123,8 +3123,8 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i val_is_zero = PyObject_RichCompareBool(val, zero, Py_EQ); Py_DECREF(zero); if (val_is_zero == -1) { - Py_DECREF(val); - return -1; + Py_DECREF(val); + return -1; } if (cmplx && PyComplex_Check(val)) {