4 ms·
Rust's rem_euclid is still wrong for negative moduli. To see why, remember that we want n = remainder + quotient * divisor. Now look at the horrible mess that i
by orlp 4y ago
Rust's rem_euclid is still wrong for negative moduli. To see why, remember that we want n = remainder + quotient * divisor. Now look at the horrible mess that is div_euclid:
> In other words, the result is self / rhs rounded to the integer q such that self >= q * rhs. If self > 0, this is equal to round towards zero (the default in Rust); if self < 0, this is equal to round towards +/- infinity.
Python gets it right. Division is simply flooring division, and modulo is defined to satisfy n = remainder + quotient * divisor. That immediately gets you all the nice behavior such as (-1) % 10 = 9, and 1 % -10 = -9.
- nextaccountic 4y agoCan you clarify why is Rust's div_euclid and rem_euclid are incorrect? For reference, here's what Rust prints for this https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a0ff242df33a7d411f803cd06cd04f40 https://play.rust-lang.org/?version=stable&mode=debug&editio... fn main() { dbg!(1_i32.rem_euclid(-10)); dbg!(-1_i32.rem_euclid(10)); } [src/main.rs:2] 1_i32.rem_euclid(-10) = 1 [src/main.rs:3] -1_i32.rem_euclid(10) = -1 I found only this issue https://github.com/rust-lang/rust/issues/87970 https://github.com/rust-lang/rust/issues/87970 but has no details Here's the discussion that lead to the implementation of those functions, from more recent to least recent, * the tracking issue https://github.com/rust-lang/rust/issues/49048 https://github.com/rust-lang/rust/issues/49048 * the RFC https://github.com/rust-lang/rfcs/pull/2169 https://github.com/rust-lang/rfcs/pull/2169 * the internals discussion https://internals.rust-lang.org/t/mathematical-modulo-operator/5952 https://internals.rust-lang.org/t/mathematical-modulo-operat... It's baffling that Rust got this wrong..
- LegionMammal978 4y agoThe operator precedence is wrong on the second one: to take -1 mod 10, you'd want to write (-1_u32).rem_euclid(10), which gives the expected result of 9.
- nextaccountic 4y agoOh, indeed. But, is the first one wrong then? But why should 1_i32.rem_euclid(-10) return -9 instead of 1?
- orlp 4y agoBecause always returning a positive result from the remainder is incredibly unnatural. You can get this behavior through Python's definition trivially using `a % abs(b)`, making rem_euclid less flexible as well. The reason it's incredibly unnatural is not obvious when looking at the remainder in isolation. But the remainder is always one half of a pair: remainder and quotient. The quotient associated with rem_euclid is batshit insane. The quotient associated with Python's modulo definition is simply floor(a/b). Note that I'm wording it very strongly when I say it is wrong. It follows its spec faithfully and isn't 'bugged', its spec is just poorly and unnaturally chosen.