是否存在一个模(而非余数)函数/运算?

在 Rust (像大多数编程语言一样)中,%操作符执行 余额操作,而不是 模数操作:

-21 modulus 4 => 3
-21 remainder 4 => -1
println!("{}", -21 % 4); // -1

然而,I 想要的模。

我找到了一个解决方案 ((a % b) + b) % b,但我不想重新发明车轮,如果已经有一个功能!

49575 次浏览

Is there a modulus (not remainder!) function / operation in Rust?

As far as I can tell, there is no modular arithmetic function.

This also happens in C, where it is common to use the workaround you mentioned: ((a % b) + b) % b.

In C, C++, D, C#, F# and Java, % is in fact the remainder. In Perl, Python or Ruby, % is the modulus.

Language developers don't always go the "correct mathematical way", so computer languages might seem weird from the strict mathematician view. The thing is that both modulus and remainder, are correct for different uses.

Modulus is more mathematical if you like, while the remainder (in the C-family) is consistent with common integer division satisfying: (a / b) * b + a % b = a; this is adopted from old Fortran. So % is better called the remainder, and I suppose Rust is being consistent with C.

You are not the first to note this:

No, Rust doesn't have a built in modulus, see this discussion for some reasons why.

Here's an example that might be handy:

///
/// Modulo that handles negative numbers, works the same as Python's `%`.
///
/// eg: `(a + b).modulo(c)`
///
pub trait ModuloSignedExt {
fn modulo(&self, n: Self) -> Self;
}
macro_rules! modulo_signed_ext_impl {
($($t:ty)*) => ($(
impl ModuloSignedExt for $t {
#[inline]
fn modulo(&self, n: Self) -> Self {
(self % n + n) % n
}
}
)*)
}
modulo_signed_ext_impl! { i8 i16 i32 i64 }

RFC 2196 adds a couple of integer methods related to euclidian division. Specifically, the rem_euclid method (example link for i32) is what you are searching for:

println!("{}", -1i32 % 4);                // -1
println!("{}", (-21i32).rem_euclid(4));   // 3

This method is available in rustc 1.38.0 (released on 2019-09-27) and above.

From the other answers I constructed:

fn n_mod_m <T: std::ops::Rem<Output = T> + std::ops::Add<Output = T> + Copy>
(n: T, m: T) -> T {
((n % m) + m) % m
}


assert_eq!(n_mod_m(-21, 4), 3);