Есть ли модуль (не остаток) функция / операция?
В 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);