-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
BUG: Fix strange behavior of infinite-step-size/underflow-case in arange #10263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BUG: Fix strange behavior of infinite-step-size/underflow-case in arange #10263
Conversation
numpy/core/src/multiarray/ctors.c
Outdated
return -1; | ||
|
||
if (val_is_zero && next_is_nonzero) { | ||
if (signbit(value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use npy_signbit
.
Thanks @xoviat, fixed! |
numpy/core/src/multiarray/ctors.c
Outdated
delta = stop - start; | ||
tmp_len = delta/step; | ||
|
||
if (tmp_len == 0.0 && delta != 0.0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a comment explaining why it is a special case
Isn't this only satisfied if step
is inf
anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser This also considers some underflow cases. eg. in master branch,
>>> m = np.float32(3.40282347E+38)
>>> e = np.float32(1.401298E-45)
>>> m
3.4028235e+38
>>> e
1.4012985e-45
>>> e/m
0.0
>>> np.arange(np.float32(0), e, m)
array([], dtype=float64)
@eric-wieser Added comments. |
numpy/core/src/multiarray/ctors.c
Outdated
delta = stop - start; | ||
tmp_len = delta/step; | ||
|
||
// Underflow and divide-by-inf check |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use C++ comments, use /* ... */
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @charris, fixed!
96b261d
to
d4d2758
Compare
numpy/core/src/multiarray/ctors.c
Outdated
if (!val) { | ||
return -1; | ||
} | ||
|
||
val_is_zero = PyObject_RichCompareBool(val, zero, Py_EQ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be an int
, not an intp
.
numpy/core/src/multiarray/ctors.c
Outdated
@@ -3049,12 +3065,19 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i | |||
} | |||
return -1; | |||
} | |||
|
|||
next_is_nonzero = PyObject_RichCompareBool(*next, zero, Py_NE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use PyObject_IsTrue
, but that might be worse on unusual types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser IMO, PyObject_RichCompareBool
is better because this is clear what we do.
numpy/core/src/multiarray/ctors.c
Outdated
val = PyNumber_TrueDivide(*next, step); | ||
Py_DECREF(*next); | ||
*next = NULL; | ||
|
||
if (!val) { | ||
return -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zero
is leaked here
Thanks @eric-wieser, fixed! |
@@ -3049,12 +3066,20 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i | |||
} | |||
return -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to DECREF
zero
here too - or better yet, just allocate it further down.
numpy/core/src/multiarray/ctors.c
Outdated
@@ -3036,7 +3051,9 @@ static npy_intp | |||
_calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, int cmplx) | |||
{ | |||
npy_intp len, tmp; | |||
PyObject *zero = PyInt_FromLong(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really you should check the return value is not NULL
here too.
5f6b735
to
41cd4e1
Compare
@eric-wieser Fixed! |
Also, I need to add some underflow-case tests. |
numpy/core/src/multiarray/ctors.c
Outdated
*next = PyNumber_Subtract(stop, start); | ||
if (!(*next)) { | ||
Py_DECREF(zero); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you move the allocation of zero
down below this if
, then you don't need to clear it up here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser If I move down zero
allocation, we need to DECREF
*next
and set NULL
to *next
when the zero
allocation failed. IMO, this is complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and set NULL to *next when the zero allocation failed.
You already need to do this
Did you mean to refer to #10271 in the PR description? Seems unrelated to me |
@eric-wieser I did not refer to that issue. Maybe @charris added this.
|
Thanks @eric-wieser, fixed! |
Added the test for some underflow cases |
numpy/core/src/multiarray/ctors.c
Outdated
|
||
val_is_zero = PyObject_RichCompareBool(val, zero, Py_EQ); | ||
Py_DECREF(zero); | ||
|
||
if (cmplx && PyComplex_Check(val)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to work out if this section needs a fix too, but I can't work out what this is even trying to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser Me t 10000 oo. I don't know why the complex case exists. This is none-sense as math.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #10332.
Can you extract |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thoughts, this is fine as is - I'll leave it open for a few more days to let someone else double-check refcounts, and then squash and merge your commits.
numpy/core/src/multiarray/ctors.c
Outdated
length = -1.0; | ||
} | ||
else { | ||
length = 1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should be 1
, as this is an integer, not double, variable. Same above.
numpy/core/src/multiarray/ctors.c
Outdated
len = -1.0; | ||
} | ||
else { | ||
len = 1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for int vs double
numpy/core/src/multiarray/ctors.c
Outdated
/* Underflow and divide-by-inf check */ | ||
if (val_is_zero && next_is_nonzero) { | ||
if (npy_signbit(value)) { | ||
len = -1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be 0
. as it is effectively ceil(-eps)
See above comments - looks like I missed a couple things when I hit approve
@eric-wieser This completely slipped my mind! I'm back, and it will be fixed in a couple of days. |
@eric-wieser Fixed, and now all green! |
return -1; | ||
} | ||
|
||
val_is_zero = PyObject_RichCompareBool(val, zero, Py_EQ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to check that this doesn't return -1, indicating an error occurred. Same above.
Thanks @eric-wieser, fixed! |
Minor style nits, but easiest to fix them myself. Thanks for the perseverance - I'll leave this for a couple days to see if there are any more comments |
@eric-wieser Just a ping. |
Thanks for the perseverance, @Licht-T - this will be in 1.15 |
This closes #10206.
The problem is
Where the step size becomes infinite.