Есть ли модуль (не остаток) функция / операция?

В Rust (как и в большинстве языков программирования) % Оператор выполняет оставшуюся операцию, а не операцию модуля. Эти операции имеют разные результаты для отрицательных чисел:

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

Тем не менее, я хочу модуль.

Я нашел обходной путь ((a % b) + b) % b, но я не хочу изобретать велосипед, если для этого уже есть функция!

2 ответа

RFC 2196 добавляет пару целочисленных методов, связанных с евклидовым делением. В частности, rem_euclid метод ( пример ссылки дляi32) это то, что вы ищете:

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

Этот метод доступен в rustc 1.38.0 (выпущено 2019-09-27) и выше.

Есть ли модуль (не остаток!) Функции / операции в Rust?

Насколько я могу судить, модульной арифметической функции не существует.

Это также происходит в C, где обычно используется обходной путь, который вы упомянули: (a % b) + b,

В C, C++, D, C#, F# и Java, % на самом деле остаток. В Perl, Python или Ruby, % это модуль.

Разработчики языка не всегда идут "правильным математическим путем", поэтому компьютерные языки могут показаться странными с точки зрения математика. Дело в том, что и модуль, и остаток являются правильными для разных целей.

Модуль, если хотите, более математический, тогда как остаток (в семействе C) соответствует общему целочисленному делению, удовлетворяющему: (a / b) * b + a % b = a; это взято из старого Фортрана. Так % лучше называть остаток, и я полагаю, что Rust соответствует C.

Вы не первый, кто это заметил:

Нет, у Rust нет встроенного модуля, посмотрите это обсуждение по некоторым причинам.

Вот пример, который может быть полезен:

///
/// 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 }

Из других ответов, которые я построил:

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);
Другие вопросы по тегам