C remainder/modulo 正参数的运算符定义

C remainder/modulo operator definition for positive arguments

我在我应该修复的程序中发现了一个函数,它定义了一个 mod 函数:

int mod(int a, int b)
{
  int i = a%b;
  if(i<0) i+=b;
  return i;
}

我被告知 ab 将永远是积极的...

嗯? if(i<0)?

参数是,that

the result of the modulo operation is an equivalence class, and any member of the class may be chosen as representative

而且只是事后才想到的

...; however, the usual representative is the least positive residue, the smallest nonnegative integer that belongs to that class, i.e. the remainder of the Euclidean division. However, other conventions are possible.

这意味着 6 % 7 可以 return 6(到目前为止还不错),而且 -1。嗯……真的吗? (让我们忽略所提供的实现并不能处理所有情况的事实。)

我知道模运算在数学上是这样的。但后来有人告诉我,C % 实际上确实 "not implement the modulo operator but the remainder"。

那么,C是如何定义%运算符的呢?

在C-Draft中我只找到

The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined.

这是否意味着 6 % 7 总是 6?还是也可以-1

Does this mean, that 6 % 7 is always 6? Or can it be -1, too?

根据this documention

Remainder

The binary operator % yields the remainder of the division of the first operand by the second (after usual arithmetic conversions).

[...]

when the type after usual arithmetic conversions is an integer type, the result is the algebraic quotient (not a fraction), rounded in implementation-defined direction (until C99)truncated towards zero (since C99)

所以6 / 7将是0,而6 % 7将是6 - 0,即6

关于模运算和等价 classes 的声明很有趣,但在 C(和大多数其他编程语言)中不是这样工作的。

而且,就算是这样,-8不也是等价的class吗?那么if(i<0) i+=b;也解决不了问题

But then someone else told me that the C % does in fact "not implement the modulo operator but the remainder".

说得好。在我链接的文档中,它被称为 "Remainder".

按照标准:

When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a. [ISO/IEC 9899:2011: 6.5.5]

这意味着a的符号保留在模数中。

 17 %  3  ->  2
 17 % -3  ->  2
-17 %  3  -> -2
-17 % -3  -> -2

所以不,6%7 不能是 -1 因为提醒必须有相同的红利符号。

永远:

  • a == (a/b)*b + a%b
  • abs(a%b) < abs(b)
  • 如果 ab 为正数,则 a % b 为正数。

从 C99 开始,

  • a/b == trunc(a/b)
  • a%b0 或具有 a 的符号。

认为 6 % 7 可能是 -1 可能是因为忽略了 ab 阳性的结果始终得到保证这一事实并且错过了变化在 C99 中。

当一个数或另一个可能为负数时,至少有三种不同的方法来定义除法和余数算法。 (有关详细信息,请参阅 this Wikipedia article -- and particularly the nice picture there。)

但是如果你知道你是用一个正数除以一个正数,那就没有任何歧义了。除法和余数的所有三个定义都表示,如果您将正数除以正数,则会得到正商和正余数。

在那里的三个选项中,C 使用了一个名为 "truncating division" 的选项。但是,同样,对于正数,它没有任何区别。 (曾几何时,由编译器决定是使用截断还是 "Euclidean" 除法,但事情只在一个定义上解决了,之前对 C 标准进行了几次修订。)

Does this mean, that 6 % 7 is always 6? Or can it be -1, too?

是的,6 % 7 总是 6(在 C 中,以及在任何三种定义下)。

另见