Question 14 of 20 Intermediate Interpretation
Why can vectorized code produce a misleading result even when it runs much faster?
Short answer
Vectorized NumPy works in fixed-size dtypes, so integers can wrap around silently and float32 sums can lose accuracy, while pure Python integers never overflow. Speed says nothing about whether the dtype was big enough.
Why
Python's int grows to fit any value. A NumPy array has a fixed dtype chosen when it was created, often from the input file. The NumPy guide shows np.power(100, 9) giving the right answer in int64 and -1486618624 in int32, with no exception.
Image data loaded as uint8 or uint16 is a common trap. Squaring pixel intensities to compute a variance, or summing millions of read counts in int32, can wrap past the maximum and produce a smaller or negative number that still looks plausible on a plot. Floats fail more quietly.
The numpy.std documentation shows a float32 array whose standard deviation comes out as 0.45000005 instead of 0.45, and recommends dtype=np.float64 for accuracy. A loop in plain Python would have used arbitrary-size integers and 64-bit floats, so rewriting a loop as one vectorized line can change the answer as well as the speed. Broadcasting can mislead too, because two arrays with the wrong orientation broadcast to a valid but meaningless shape.
The defenses are cheap. Check np.iinfo for the dtype's range, cast to int64 or float64 before reductions, compare a vectorized function with a slow reference on a small input, and assert output shapes.
A strong answer covers
- Fixed-size dtypes can overflow without an error
- Python int is arbitrary precision, NumPy integers are not
- float32 reductions lose accuracy
- Wrong-axis broadcasting gives a valid but meaningless shape
- Cast before reducing and test against a slow reference
Common mistakes
- Assuming NumPy raises an error on integer overflow the way it might for a division by zero warning
- Keeping image intensities in uint8 while computing squared differences
- Validating a vectorized rewrite only by timing it, not by comparing outputs with the loop it replaced
The interviewer might ask next
How would you choose dtypes when loading a 16-bit microscopy stack for quantification?