Why does my NumPy integer calculation give a wrong or negative result?
Short answer
NumPy integers have a fixed size, so a value that exceeds the type's range wraps around silently, sometimes to a negative number. Choose a wider dtype, or convert to float, when values can grow large.
The short version
Unlike Python's own integers, NumPy integers have a fixed bit width, so a result that exceeds the type's range wraps around instead of growing. That is why a sum can come out smaller, or even negative, than you expect. Fix it by using a wider integer dtype, or by converting to float, when your values can get large.
Seeing the overflow
import numpy as np
x = np.array([120, 100], dtype=np.int8)
print(x[0] + x[1]) # -36, not 220
An int8 can only hold values from -128 to 127. The true answer 220 does not fit, so it wraps around to -36. NumPy may warn, but the calculation still returns the wrong number.
Why Python itself does not do this
Plain Python integers grow without limit, so 120 + 100 is always 220. NumPy trades that safety for speed and memory, storing each integer in a fixed number of bytes. This is usually invisible, until a value pushes past the edge of its type.
The fix: a wider dtype
Choose a type big enough for the largest value you expect. The default integer on most platforms is 64-bit, which is huge, so the problem mainly appears when you deliberately narrowed the dtype to save memory.
np.array([120, 100], dtype=np.int64).sum() # 220, correct
If you downcast to save memory (a sensible optimisation), make sure the range still comfortably holds your values, including intermediate results of any arithmetic.
Watch out during aggregation
Overflow is especially sneaky when summing a long array of small integers, because the running total can exceed the element type even though no single value does. Sum into a wider type to be safe.
small = np.array([100] * 1000, dtype=np.int8)
small.sum(dtype=np.int64) # force a wide accumulator
Passing dtype to sum tells NumPy to accumulate in that wider type, avoiding overflow in the total.
Converting to float
If exact integer behaviour is not required, converting to float sidesteps integer overflow, because floats have an enormous range.
x.astype(np.float64).sum() # 220.0
The trade-off is that very large integers lose exactness as floats, so use this when approximate large values are acceptable, not for exact counts or identifiers.
The habit to build
When you set an integer dtype narrower than the default, pause and check the range against your data and its sums. A silent wrap is worse than a crash, because the wrong number flows on undetected, so choose the width deliberately whenever you leave the default.