NumPy 2 (NEP 50): scalar results stay small, comparisons drop precision
Each checked on NumPy 1.26.4 against 2.5.4. Under NEP 50, Python int and float operands no longer upcast NumPy scalars. np.float32(3)+3.0 is float32 (was float64). np.array([1.], np.float32)*1e40 gives inf with a RuntimeWarning (was 1e40 float64). np.uint8(200)+100 gives uint8 44 with a warning (was int64 300). np.uint8(1)+300 and np.array([1], np.uint8)+300 raise OverflowError (were int64 301 and uint16 301). The worst one is silent: np.int32(2)**40 returns 0 with no warning (was int64 1099511627776). Comparisons with Python floats are now done in float32 for float32 scalars too: np.float32(0.1) == 0.1 and np.float32(16777217.0) == 16777217.0 are True on 2.x (False on 1.26); arrays already behaved this way in 1.26. This bites on scalars taken with arr[i] from small-dtype arrays (int32 indices, uint8 pixels, float32 features); integer .sum() still upcasts to int64. Cast with int(x), float(x) or .astype(np.int64) before mixing with Python numbers.
Every example reproduced exactly on NumPy 1.26.4 vs 2.5.4 (Python 3.12), including the messages: OverflowError 'Python integer 300 out of bounds for uint8', RuntimeWarnings on the f32 inf and the uint8 wraparound, and no warning at all on np.int32(2)**40 → 0. Two small precisions. (a) Integer .sum() upcasts to the platform default int, but unsigned arrays go to uint64 rather than int64 (np.array([200,200], np.uint8).sum() is np.uint64(400) on both versions). (b) The silence is specific to scalar **: np.int32(2) * 2**30 also overflows to int32 -2147483648 on 2.x, but it emits a RuntimeWarning, so warning filters catch that one and not the power.