【问题标题】:What's the difference between “mod” and “remainder”?“mod”和“remainder”有什么区别?
【发布时间】:2012-11-20 22:29:39
【问题描述】:

朋友说“mod”和“remainder”是有区别的。

如果是这样,C 和 C++ 的区别是什么? '%' 在 C 中是表示“mod”还是“rem”?

【问题讨论】:

  • 对于负操作数可能定义不明确。
  • @BasileStarynkevitch:你的意思是当出现负操作数时差异取决于实现吗?我需要“是”或“否”,因为这个问题给我带来了麻烦。谢谢!
  • % 是余数。在此处回答详细信息-> blogs.msdn.com/b/ericlippert/archive/2011/12/05/…
  • @David:问题是关于这些术语的含义。如果你说这个问题没有意义,尽管有几个人按照提问者的意图理解它,那么我认为你必须更具体地说明“意思”这个词的意思;-)
  • @SteveJessop 这些术语有不同的含义。如果问题可以指定使用这些相互竞争的含义中的哪一个,那么就有可能说出它们的不同之处。

标签: c math operators


【解决方案1】:

模数和余数之间存在差异。例如:

-21 mod 43 因为 -21 + 4 x 63

但是-21 除以4 得到-5 余数为-1

对于正值,没有区别。

【讨论】:

  • @Jinxiao:在 C89 中它是实现定义的:% 总是余数,但它可能是模数(即总是正数),因为在 C89整数除法被允许向负无穷而不是向 0 舍入。因此在 C89 中,-5 / 2 可以是 -2,余数为 -1,或 -3,余数为 1,实现只需要记录哪个。 C99 移除了灵活性,所以现在-5 / 2 始终是-2
  • 其实并不清楚模数是什么。似乎有许多不同的定义,具体取决于上下文和语言。请参阅有关 modulo_operation 的维基百科文章。在某些情况下,它实际上与余数相同。
  • 有人能解释一下第一次计算的步骤吗? -21 mod 43?为什么计算是-21 + 4 x 6
  • @OzEdri 要获得某个数字 mod 4,您可以添加任何 4 的整数倍,以获得 0 到 3 之间的数字。对于 -21,该整数为 6,因为 -21 + 4 x 6 介于 0 之间和 3.
  • 其实这是错误的。根据定义(见en.wikipedia.org/wiki/Euclidean_division)余数是一个正数,所以-21除以4得到-6余数为3
【解决方案2】:

'%' 在 C 中是表示“mod”还是“rem”?

在 C 中,%余数1

...,/ 运算符的结果是丢弃任何小数部分的代数商...(这通常称为“向零截断”。)C11dr §6.5.5 6

% 运算符的操作数应为整数类型。 C11dr §6.5.5 2

/ 运算符的结果是第一个操作数除以第二个的商; % 运算符的结果是 remainder ... C11dr §6.5.5 5


“mod”和“remainder”有什么区别?

C 没有定义“mod”或“模”运算符/函数,例如 Euclidean divisionother modulo 中使用的整数模函数。

C 定义余数

让我们将% 运算符的“余数”与欧几里得“mod”进行比较。

a 为负时,“欧几里得模”不同于C 的a%b 运算。

 // a % b, the remainder after an integer division that truncates toward 0.
 7 %  3 -->  1  
 7 % -3 -->  1  
-7 %  3 --> -1  
-7 % -3 --> -1   

“Mod”或欧几里得除法中的模数。结果始终为 0 或正数。

 7 modulo  3 -->  1
 7 modulo -3 -->  1
-7 modulo  3 -->  2
-7 modulo -3 -->  2

候选模码:

int modulo_Euclidean(int a, int b) {
  int m = a % b;
  if (m < 0) {
    // m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
    m = (b < 0) ? m - b : m + b;
  }
  return m;
}

关于浮点数的注意事项:double fmod(double x, double y),虽然叫“fmod”,但与欧几里德除法“mod”不同,但类似于C整数余数:

fmod 函数计算x/y的浮点余数。 C11dr §7.12.10.1 2

fmod( 7,  3) -->  1.0
fmod( 7, -3) -->  1.0
fmod(-7,  3) --> -1.0
fmod(-7, -3) --> -1.0

Disambiguation:C 也有一个类似的命名函数double modf(double value, double *iptr),它将参数值分成整数和小数部分,每个部分都具有与参数相同的类型和符号。除了名称相似之外,这与这里的“mod”讨论几乎没有关系。


[编辑 2020 年 12 月]

对于那些在所有情况下都需要适当功能的人,改进的 modulo_Euclidean() 1) 检测到 mod(x,0) 和 2) modulo_Euclidean2(INT_MIN, -1) 的良好且没有 UB 结果。灵感来自4 different implementations of modulo with fully defined behavior

int modulo_Euclidean2(int a, int b) {
  if (b == 0) TBD_Code(); // perhaps return -1 to indicate failure?
  if (b == -1) return 0; // This test needed to prevent UB of `INT_MIN % -1`.
  int m = a % b;
  if (m < 0) {
    // m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
    m = (b < 0) ? m - b : m + b;
  }
  return m;
}

1 在 C99 之前,C 对 % 的定义仍然是除法的余数,但后来 / 允许向下舍入而不是“截断”趋向于零”。见Why do you get different values for integer division in C89?。因此,通过一些 C99 之前的编译,% 代码可以像欧几里得除法“mod”一样工作。上面的modulo_Euclidean() 也可以与这个备用的老式剩余部分一起使用。

【讨论】:

【解决方案3】:

余数符号与除数相同,模数符号与除数相同。

余数只是两个整数之间的算术除法后的剩余部分,而模数是余数和除数的和,当它们的符号相反时,以及当余数和除数的符号相同时,算术除法后的剩余部分。

余数示例:

10 % 3 = 1 [这里可除数是10,它是正符号的,所以结果也将是正符号的]

-10 % 3 = -1 [这里可除数是-10,它是负号的,所以结果也是负号的]

10 % -3 = 1 [这里可除数是10,它是正符号的,所以结果也将是正符号的]

-10 % -3 = -1 [这里可除数是-10,它是负号的,所以结果也将是负号的]

模数示例:

5 % 3 = 2 [这里可除数是5,它是正符号的,所以余数也将是正符号的,除数也是正符号的。由于余数和除数的符号相同,结果将与余数相同]

-5 % 3 = 1 [这里除数是-5,它是负号的,所以余数也将是负号的,除数是正号的。由于余数和除数的符号相反,结果将是余数和除数之和 -2 + 3 = 1]

5 % -3 = -1 [这里可除数是5,它是正符号的,所以余数也将是正符号,除数是负符号。由于余数和除数的符号相反,结果将是余数和除数之和 2 + -3 = -1]

-5 % -3 = -2 [这里除数是-5,它是负号的,所以余数也将是负号的,除数也是负号的。由于余数和除数的符号相同,结果将与余数相同]

我希望这能清楚地区分余数和模数。

【讨论】:

    【解决方案4】:

    在 C 和 C++ 以及许多语言中,% 是余数而不是模运算符。

    例如在运算-21 / 4 中,整数部分为-5,小数部分为-.25。余数是除数的小数部分,所以我们的余数是-1。 JavaScript 使用余数运算符并确认这一点

    console.log(-21 % 4 == -1);

    模数运算符就像你有一个“时钟”。想象一个圆,分别在 12 点钟、3 点钟、6 点钟和 9 点钟位置具有值 0、1、2 和 3。将商时间按顺时针方向按顺时针方向移动,我们就能得到模运算的结果,或者,在我们的示例中,逆时针方向为负商,得到 3。

    注意: 模数始终与除数同号,余数与商同号。当至少一个为负时,将除数和余数相加得到模数。

    【讨论】:

    • 你的意思是余数的符号总是与红利的符号相同吗? 7 / -3 = -2 的商,但 7 rem -3 = 1
    【解决方案5】:

    模数,在您所指的模算术中,是算术除法后剩余的值或剩余值。这通常称为余数。 % 正式地是 C / C++ 中的余数运算符。示例:

    7 % 3 = 1  // dividend % divisor = remainder
    

    剩下要讨论的是如何处理这个 % 操作的负输入。现代 C 和 C++ 会为此运算生成一个有符号余数,其中结果的符号始终与被除数输入匹配,而不考虑除数输入的符号。

    【讨论】:

      【解决方案6】:
      % is a remainder(leftover after dividend / divisor) NOT modulus. 
      

      您可以使用关系的余数(%)编写自己的模函数

        ((n%m)+m)%m
      
        where `n` is the given number and `m` is the modulus
      

      找出范围 n = (-7,7) 和 m = 3 的余数和模值之间的差

      n       -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  
      ------------------------------------------------------------------------- 
      %(-m)   -1  0 -2 -1  0 -2 -1  0  1  2  0  1  2  0  1  =>  remainder
      % m     -1  0 -2 -1  0 -2 -1  0  1  2  0  1  2  0  1  =>  remainder
      mod m    2  0  1  2  0  1  2  0  1  2  0  1  2  0  1  =>  ((n%m)+m)%m
      mod(-m) -1  0 -2 -1  0 -2 -1  0 -2 -1  0 -2 -1  0 -2  =>  ((n%m)+m)%m
      

      要记住的提示:

      n%(-m)   = +(remainder)
      (-n)%(m) = -(remainder)
      sign of 'm' doesn't matter
      
      n mod (-m) = -(result)
      (-n) mod m = +(result)
      sign of 'n' doesn't matter
      
      For +ve 'n' and '%(-m)' or '%m' or 'mod m' gives the same remainder
      

      【讨论】:

        【解决方案7】:

        在数学中,模运算的结果是欧几里得除法的余数。然而,其他约定也是可能的。计算机和计算器有多种存储和表示数字的方式;因此他们对模运算的定义取决于编程语言和/或底层硬件。

         7 modulo  3 -->  1  
         7 modulo -3 --> -2 
        -7 modulo  3 -->  2  
        -7 modulo -3 --> -1 
        

        【讨论】:

        • wiki Euclidean division 断言0 ≤ r &lt; |b| 这意味着余数也称为“模运算”。始终至少为 0。您使用什么定义导致 -2 和 -1?
        • 先生,我不知道,但我只是谷歌 7 modulo -3 --> -2 .and.-7 modulo -3 --> -1 请先生解释一下为什么会这样
        • Google 使用与 Wiki 欧几里得除法(如 Raymond T. Boute 所述)不同的模数定义(有符号模数?)。 This 更多地讨论了差异。故事的寓意:a%ba modulo ba,b 为正时具有相同的含义。 C99 用负值精确定义 %。 C 将此称为“余数”。“模”在世界上对负值有多种定义。C 规范仅在正数的上下文中使用“模”。
        猜你喜欢
        • 1970-01-01
        • 2017-04-19
        • 2021-05-27
        • 1970-01-01
        • 2010-10-02
        • 2011-12-12
        • 2010-09-16
        • 2012-03-14
        相关资源
        最近更新 更多