Is there a modulus (not remainder) function / operation?
Asked Answered
E

4

140

In Rust (like most programming languages), the % operator performs the remainder operation, not the modulus operation. These operations have different results for negative numbers:

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

However, I want the modulus.

I found a workaround ((a % b) + b) % b, but I don't want to reinvent the wheel if there's already a function for that!

Ellery answered 3/7, 2015 at 15:39 Comment(3)
Any reason to use the term modulus instead of modulo (which is more common AFAICS).Alexandria
They might have studied somewhere where the term modulus is used, not knowing that different institutions tend to differ in vocabulary.Oliveolivegreen
For powers of two, you can do something like -21 & (4 - 1), granted it's an integer.Pettus
A
125

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.

Angers answered 3/8, 2019 at 20:53 Comment(3)
They are also implemented for unsigned variants, although it is not possible to figure out what they do from that documentation. I would also mention div_euclid() for completeness. But this should be the selected answer anyway.Cinerarium
@Cinerarium when you see int_impl! you can go to this file and see the actual implementation: github.com/rust-lang/rust/blob/…Microlith
such a misnomer. remainder should be modulos and modulos remainder.Sextans
N
43

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:

Nagy answered 3/7, 2015 at 16:1 Comment(7)
I, as a C/C++ programmer, am embarrassed that I didn't know that % works in C that way, too...Ellery
Isn't this a gap in Rust?Ellery
Well, as you expect, this is not something mathematicians enjoy. And i would not say it is a gap, for all this family of languages % is just the remainder.Nagy
I'll go with % being the remainder, but not having support for modulus sucks...Ellery
@Nagy As I write this, the answer above shows (a % b) + b as a way to calculate the modulus, but I'm pretty sure what you meant to write is this: ((a % b) + b) % b.Messinger
(a / b) * b + a mod b = a is satisfied if / rounds toward -∞.Italianize
It has been added now, see next comment.Butyraldehyde
A
10

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 }
Alexandria answered 2/1, 2017 at 6:1 Comment(1)
Would modulo_signed_ext_impl! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } be better?Anaanabaena
A
-4

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);
Anaanabaena answered 25/8, 2020 at 23:27 Comment(2)
If you're going to use that on integers, how is it better than the built-in rem_euclid mentioned in Lukas Kalbertodt's answer?Evangelistic
I find this explicit function easier to mentally parse than the opaque .rem_euclid()Anaanabaena

© 2022 - 2024 — McMap. All rights reserved.