310. f64::max — The Fold That Quietly Swallows NaN
f64::NAN.max(3.0) is 3.0. A running max over data with a NaN in it returns a perfectly clean-looking number — and the is_nan check downstream swears nothing went wrong.
f64::max and f64::min follow IEEE 754’s maxNum/minNum semantics: if one operand is NaN, they return the other one. So NaN doesn’t poison the result the way it does with + or * — it silently drops out:
| |
Sometimes that’s exactly what you want — treat NaN as “no data” and take the max of what’s left. But if a NaN in the input means the computation upstream went wrong, checking the result tells you nothing: the fold already laundered it.
The stable way to make NaN surface is total_cmp (the same total ordering from bite 101). In IEEE total order, positive NaN sorts above +inf, so a NaN in the data becomes the maximum instead of disappearing:
| |
(There are NaN-propagating f64::maximum / f64::minimum methods in the works, but they’re still unstable — total_cmp is the fix on stable.)
Like the subnormals in bite 309, this is a case where the value you’re inspecting passes every check while the data behind it lies. Decide explicitly: NaN-ignoring (f64::max) or NaN-surfacing (max_by(total_cmp)) — just don’t let the default decide for you.