A position that changes sign
Suppose a fictional position contains 120 contracts and a trade adds 20. The exact new position is 140 contracts. An 8-bit signed integer can store only −128 through 127, so 140 does not fit.
int8 arrays keeps that dtype and wraps the result to −116. By contrast, built-in Python integers return 140. This example was executed with Python 3.14.4 and NumPy 2.5.1.import numpy as np
position = np.array([120], dtype=np.int8)
trade = np.array([20], dtype=np.int8)
wrapped = position + trade
wide = position.astype(np.int16) + trade.astype(np.int16)
too_late = wrapped.astype(np.int16)
print(wrapped.tolist(), wrapped.dtype)
# [-116] int8
print(wide.tolist(), wide.dtype)
# [140] int16
print(too_late.tolist(), too_late.dtype)
# [-116] int16
print(120 + 20)
# 140int16 preserves the already incorrect −116; it cannot reconstruct 140. The wider inputs produce 140 because that result fits int16. A wider fixed-width type still has a limit.Where does −116 come from?
10001100. Read as unsigned, this means 140. Read as a signed two’s-complement value, the leading bit contributes −128, giving . Equivalently, .For a signed two’s-complement integer of width , the range is
The corresponding unsigned range is through . For example:
| NumPy dtype | Minimum | Maximum |
|---|---|---|
int8 | −128 | 127 |
uint8 | 0 | 255 |
int16 | −32,768 | 32,767 |
np.iinfo(dtype).min and .max report these bounds. Signedness changes how the bit patterns are interpreted; unsigned storage does not remove the upper limit.Treat the representation as part of the calculation
Overflow behaviour belongs to the particular language, library and operation. Do not infer that every integer implementation wraps as this NumPy array does. NumPy’s current documentation also distinguishes scalar overflow warnings from array arithmetic: these array additions produce no warning. Absence of a warning does not establish correctness.
int uses arbitrary precision, so it has no fixed 8-bit or 64-bit arithmetic boundary. Larger values need more memory and computation; arbitrary precision does not mean infinite machine capacity. An array created with dtype=int still uses a fixed-width NumPy integer dtype.Check the unsigned case
uint8 arrays for both inputs, what are the result, the result cast afterward to int16, and the result when both inputs are cast to int16 first?uint8 wraps modulo 256, giving 4. Casting that result afterward still gives 4. Casting both inputs first gives 260 in int16. The positive wrapped value can look plausible, so a negative-result check alone would miss this failure.