-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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: numpy 2.0 dividing np.uint8 by python int leads to OverflowError #25639
Comments
In more testing, the same difference in version behavior occurs for the |
This is happening because we enabled NEP 50 behavior by default, see NEP 50 for more details: https://numpy.org/neps/nep-0050-scalar-promotion.html. Going forward, we will no longer do value-based promotion for scalars. If you instead would like it to silently truncate, you could use a 0-d array. If you want neither, you need to make sure that both dtypes are big enough such that no overflow would happen. |
That said: it would be nice to make it work for the first example (when the result is a float). That would require a careful promoter I guess. |
It isn't that obvious to me that there should be any value-based promotion needed here. I might expect this behavior using Either way, I cannot find this change clearly called out in the release notes or migration guide. I suggest that this overall change, including all operator behavior, needs a much larger description there. |
It does say that this applies to operations "like" addition and multiplication, I can understand it is maybe confusing, but listing all affected functions also doesn't make sense (since basically everything is affected). Do you have a suggestion? As to So, while it would be great to generally just use floats for operations that are undefined on integers, I am unsure if I want to prioritize |
This makes sense to me since the operation is performed with two integers and outputs a new integer.
After reading again, the line you might have quoted in the NEP helps (quoted below), although adding another example to
|
When I read the first figure in the NEP, I might expect this flow of promotion np.uint8(128) / 256 -> np.uint8(128) / np.uint16(256) -> np.float64(0.5) This works when being explicit about the type, i.e. Another observation is that one of the goals is that:
In my testing this is not true for # a np.ndarray[np.float64] in both v1 and v2
a = np.array([15], dtype=np.uint8) / 256
# OverflowError only in v2
a = np.uint8(15) / 256 |
Aha, thanks for noticing that! That isn't intentional of course. Seems at least the divide ufunc (which arrays use for the (There should be a few other ufuncs similar to division, although most of them are probably unary, and for unary ones there is a hack in place that should them work, IIRC.) So we need to align the scalar division. Not quite sure how easy that is (the scalar code is confusing), although in the worst case we probably can make it punt to the ufunc (which is however much slower). |
It's annoying. This works, by making things slow (it also makes diff --git a/numpy/_core/src/umath/scalarmath.c.src b/numpy/_core/src/umath/scalarmath.c.src
index 5b60ebff16..3cf551cb51 100644
--- a/numpy/_core/src/umath/scalarmath.c.src
+++ b/numpy/_core/src/umath/scalarmath.c.src
@@ -1291,6 +1291,18 @@ static PyObject *
*/
#if defined(IS_longdouble) || defined(IS_clongdouble)
Py_RETURN_NOTIMPLEMENTED;
+#endif
+ case CONVERT_PYSCALAR:
+ /*
+ * Python float, int, complex. For true-divide, we fall through
+ * to the ufunc (we reach here for integers mainly).
+ * TODO: This is slow, but makes `uint(8) / 10` work.
+ */
+#ifndef IS_true_divide
+ if (@NAME@_setitem(other, (char *)&other_val, NULL) < 0) {
+ return NULL;
+ }
+ break;
#endif
case PROMOTION_REQUIRED:
/*
@@ -1302,11 +1314,6 @@ static PyObject *
* correctly. (e.g. `uint8 * int8` cannot warn).
*/
return PyGenericArrType_Type.tp_as_number->nb_@oper@(a,b);
- case CONVERT_PYSCALAR:
- if (@NAME@_setitem(other, (char *)&other_val, NULL) < 0) {
- return NULL;
- }
- break;
default:
assert(0); /* error was checked already, impossible to reach */
return NULL; |
There is a PR to add a section on this to the migration guide, if you would like to comment, see #25683. Thanks for the prompting to add it. |
Describe the issue:
When preparing for upgrading to numpy 2.0, I'm seeing differences in handling of division of numpy integer types with python integer types.
Reproduce the code example:
Error message:
OverflowError: Python integer 256 out of bounds for uint8
Python and NumPy Versions:
2.0.0.dev0+git20240113.d2f60ff
3.10.13 (main, Jan 10 2024, 19:45:45) [GCC 9.4.0]
Runtime Environment:
Context for the issue:
Is this a planned change for numpy 2.0? I could not find any indication in the release notes or migration guide. If so, would the recommended workaround be to first cast
a
, in the code example, tofloat64
or auint
type that can handle larger values? Or perhaps convert the pythonint
into a suitable numpy integer type?The text was updated successfully, but these errors were encountered: