245. rem_euclid — The Modulo That Never Goes Negative
-1 % 5 is -1 in Rust, not 4 — % keeps the sign of the dividend. When you want a true wrap-around index or clock value, (-1i32).rem_euclid(5) gives you the 4 you actually meant.
Why % bites you
Rust’s % is a remainder, not a mathematical modulo. Its result takes the sign of the left operand:
| |
That’s fine for the positive case, but the moment a negative number sneaks in — a decrementing index, an offset that can go below zero — you get a negative result. Feed that into arr[idx as usize] and you either panic or cast into a giant number.
rem_euclid always lands in [0, n)
| |
For a positive divisor, rem_euclid is guaranteed to return a non-negative result strictly less than the divisor — exactly what “wrap around” should mean.
Where it pays off: wrapping an index
Stepping backwards through a ring buffer is the textbook case. With % you’d have to add the length back in by hand to avoid going negative:
| |
No + len fixup, no branch on “did it go negative.” The same trick handles clock arithmetic ((hour + delta).rem_euclid(24)) and angle normalization.
div_euclid is its partner: (-8).div_euclid(3) == -3, and the identity a == b * a.div_euclid(b) + a.rem_euclid(b) always holds. Whenever you catch yourself writing ((x % n) + n) % n to force a positive remainder, that’s rem_euclid spelled the hard way.