Skip to content

overflow not caught on operators with int32 array (Trac #2133) #593

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

Closed
numpy-gitbot opened this issue Oct 19, 2012 · 6 comments
Closed

overflow not caught on operators with int32 array (Trac #2133) #593

numpy-gitbot opened this issue Oct 19, 2012 · 6 comments

Comments

@numpy-gitbot
Copy link

Original ticket http://projects.scipy.org/numpy/ticket/2133 on 2012-05-16 by trac user mwtoews, assigned to unknown.

I see good overflow warnings operations on int32 scalars, but not for int32 arrays:

import numpy as np

# Case 1: Good, proper data types are used to avoid overflow
np.array([1], dtype=np.long) + np.int32(2**31 - 1)
# array([2147483648], dtype=int64)

# Case 2: Bad, overflow happens and no warning raised
np.array([1], dtype=np.int32) + np.int32(2**31 - 1)
# array([-2147483648])

# Case 3: Similar bad, array vs. array
np.array([1], dtype=np.int32) + np.array([2**31 - 1], dtype=np.int32)
# array([-2147483648])

# Case 4: Better, a warning is raised
np.int32(1) + np.int32(2**31 - 1)
# __main__:1: RuntimeWarning: overflow encountered in long_scalars
# -2147483648

Here is what I can determine between operator op between arrays or scalars:

  1. array-long op scalar-32 = array-long, all good
  2. array-32 op scalar-32 = array-32, no overflow warning!
  3. array-32 op array-32 = array-32, no overflow warning!
  4. scalar-32 op scalar-32 = scalar-32, helpful overflow warning

I would expect an overflow runtime warning for cases 2 and 3, similar to case 4.

These results are with NumPy 1.6.1/Python 2.5.1 on Windows 32-bit, which I installed from numpy-unoptimized-1.6.1.win32-py2.5.exe from [http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy ~gohlke], but are reproducible on 64-bit Linux.

@numpy-gitbot
Copy link
Author

@rgommers wrote on 2012-05-19

Likely related to #2350.

@njsmith
Copy link
Member

njsmith commented Jan 3, 2013

This is unrelated to #2350; the overflow checking code for floating point and integers is totally different. (The former relies on some special IEEE-754 features that can only be accessed through platform specific code and #2350 is that apparently our platform specific code is buggy; integer overflow is checked directly by hand in our own C code. grep for npy_set_floatstatus_overflow in scalarmathmodule.c.src to see...)

The bug here is very simple: we have two complete sets of arithmetic functions for integers, one in scalarmathmodule.c.src and one in loops.c.src. The former code implements overflow checking, the latter code doesn't. We should just fix this. (Ideally by moving the checks into loops.c.src and then throwing out scalarmathmodule.c.src entirely, I guess -- the ufunc loops have a funny calling convention if you're in a scalar, but so what. There's still no reason you can't call them directly to implement scalar arithmetic and I can't imagine that doing a 1-element for loop is measurably slower than using a custom function that has just taken out the for loop.)

@peterjc
Copy link
Contributor

peterjc commented Jan 4, 2013

I presume in addition to int32, this bug can be generalised to cover the other integer types, e.g. uint8 (as shown in my example below), int8, uint16, int16, uint32, int64, uint64

>>> import numpy as np
>>> np.__version__
'1.6.1'
>>> A = np.zeros((100,100), np.uint8) # Matrix could be very big
>>> A[3,4] = 255 # Max value, setting up next step in example
>>> A[3,4]
255
>>> A[3,4] += 1 # Silently overflows on NumPy 1.6
>>> A[3,4]
0

In this use case, I am working with the topology of a graph allowing multiple edges held as an integer adjacency matrix, A. I would calculate things like A^n for paths of length n, and also make changes to A directly (e.g. adding edges). The motivation to use the low range types like np.uint8 (unsigned) is to limit the memory while working with large networks. In this usage I do not need negative entries.

See http://mail.scipy.org/pipermail/numpy-discussion/2013-January/064948.html and http://mail.scipy.org/pipermail/numpy-discussion/2013-January/064949.html

@njsmith
Copy link
Member

njsmith commented Jan 4, 2013

@peterjc: Right, if you look at scalarmathmodule.c.src and loops.c.src you'll see that all that the code for all the different integer widths is generated from the same template, so whatever applies to one width applies to all.

@mattip
Copy link
Member

mattip commented Apr 26, 2018

duplicate of #8987, since there is more discussion there should we close this one?

@seberg
Copy link
Member

seberg commented May 14, 2019

Closing as duplicate of gh-8987 as mentioned already by Matti (integer overflow issue).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants