【问题标题】:Is there a modulus (not remainder) function / operation?是否有模数(不是余数)函数/运算?
【发布时间】:2015-09-21 12:07:09
【问题描述】:

在 Rust(与大多数编程语言一样)中,% 运算符执行 remainder 操作,而不是 modulus 操作。这些operations have different results for negative numbers:

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

但是,我想要模数。

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

【问题讨论】:

  • 任何理由使用术语modulus 而不是modulo(这是更常见的AFAICS)。
  • 他们可能在某个地方研究过使用模数一词,但不知道不同的机构在词汇上往往会有所不同。
  • 对于 2 的幂,您可以执行 -21 & (4 - 1) 之类的操作,前提是它是一个整数。

标签: rust modulo


【解决方案1】:

RFC 2196 添加了几个与欧几里得除法相关的整数方法。具体来说,rem_euclid 方法 (example link for i32) 就是您要搜索的内容:

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

此方法在rustc 1.38.0(2019-09-27发布)及以上版本可用。

【讨论】:

  • 它们也适用于未签名的变体,尽管无法从该文档中弄清楚它们的作用。为了完整起见,我还要提到div_euclid()。但无论如何,这应该是选定的答案。
【解决方案2】:

Rust 中有模数(不是余数!)函数/运算吗?

据我所知,没有模算术函数。

这也发生在 C 中,通常使用您提到的解决方法:((a % b) + b) % b。

在 C、C++、D、C#、F# 和 Java 中,% 实际上是余数。在 Perl、Python 或 Ruby 中,% 是模数。

语言开发人员并不总是采用“正确的数学方式”,因此从严格的数学家的角度来看,计算机语言可能看起来很奇怪。问题是模数和余数对于不同的用途都是正确的。

如果您愿意,模数更数学化,而余数(在 C 系列中)与常见的整数除法一致,满足:(a / b) * b + a % b = a;这是从旧的 Fortran 采用的。所以% 最好称为余数,我想Rust 与C 是一致的。

你不是第一个注意到这一点的人:

【讨论】:

  • 作为一名 C/C++ 程序员,我很尴尬,因为我不知道 % 在 C 中也是这样工作的......
  • 这不是 Rust 中的空白吗?
  • 我会选择 % 作为余数,但不支持模数很糟糕......
  • @JosEduSol 在我写这篇文章时,上面的答案显示(a % b) + b 是一种计算模数的方法,但我很确定你要写的是:((a % b) + b) % b。跨度>
  • (a / b) * b + a mod b = a 满足如果 / 向 -∞ 舍入。
【解决方案3】:

不,Rust 没有内置模数,出于某些原因,请参阅 this discussion。

这是一个可能很方便的例子:

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

【讨论】:

  • modulo_signed_ext_impl! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } 会更好吗?
【解决方案4】:

根据我构建的其他答案:

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);

【讨论】:

猜你喜欢
  • 2021-06-12
  • 1970-01-01
  • 2013-07-22
  • 2014-08-20
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多