在早期的课程中,我被教导n % d = r
并将其视为n = d*q + r
,其中d
是除数,q
是商,{{{ 1}}是余数(注意余数永远不会是负数)。
例如,r
为-111 mod 11
,因为10
(与-111 = -11*-11 + 10
相对,因为这会给我们带来负余数)。
但是,在打印-111 = -11*10 -1
的结果时,-111 % 11
是结果,而不是-1
。为什么?这在技术上是不是错了?
答案 0 :(得分:20)
简答:
(a/b)*b + a%b
等于a
的标准保证。
在C99中,除法/
的结果将截断为零。 %
运算符的结果将是肯定的,在本例中为-1
。
在C89中,对于负操作数,除法/
的结果可以被截断。因此%
运算符的结果也与机器有关。
长答案:
来自C99 6.5.5
5 /运算符的结果是第一个操作数除以的商 第二; %运算符的结果是余数。在这两个操作中,如果值为 第二个操作数为零,行为未定义。
6当整数被分割时,/运算符的结果是任意的代数商 分数部分丢弃。如果商a / b是可表示的,则表达式 (a / b)* b + a%b应等于a;否则,a / b和a%b的行为都是 未定义。
在同一页面上的脚注解释/
如何运作,它说:
这通常被称为“截断为零”。
根据此规则,-111 / 11
只能是-10
,而不是1.由于(a/b)*b + a%b
必须等于a
,我们-111 % 11
是{ {1}}。
然而,K& R第2.5章给出了不同的答案:
/和%的结果符号的截断方向与负操作数的机器相关,就像上溢或下溢时采取的操作一样。
根据这一点,-1
或-1
可以是合法的结果。
原因在于C89 3.3.5:
当整数被划分并且除法不精确时,如果两个操作数都是正数,则/运算符的结果是小于代数商的最大整数,并且%运算符的结果是正数。如果任一操作数为负,则/运算符的结果是小于代数商的最大整数还是大于代数商的最小整数是实现定义的,这是%运算符的结果的符号。如果商a / b是可表示的,则表达式(a / b)* b + a%b应等于a。
原来是从C89到C99的变化。
C99理由6.5.5提供了一些历史原因:
在C89中,涉及负操作数的整数划分可以以实现定义的方式向上或向下舍入;目的是避免在运行时代码中产生开销以检查特殊情况并强制执行特定行为。但是,在Fortran中,结果将始终截断为零,并且数字编程社区似乎可以接受开销。因此,C99现在需要类似的行为,这应该有助于将代码从Fortran移植到C.本文档的第7.20.6.2节中的表说明了所需的语义。
这是§7.20.6.2中的表格:
10
答案 1 :(得分:6)
对于模数,-1将是错误的答案。
C %
运算符是余数运算符,而不是模数运算符 - 对于余数,允许10或-1。
答案 2 :(得分:4)
%
运算符的实现使得a == b * (a / b) + (a % b)
为真,我们使用整数除法。
在这种情况下,-111 / 11
为-10
,-111 == 11 * -10 + x
满足x == -1
。