请解释以下原因,因为从数学上讲-2
,两种情况下的正确答案都是:
int a=7%-5; //Assigns 2 to a
int a=-7%5; //Assigns -2 to a
代码在 C 中。
7 / -5 = -1
有余数2
,因为-1 * -5 + 2 = 5 + 2 = 7
.
-7 / 5 = -1
有余数-2
,因为-1 * 5 + (-2) = -5 - 2 = -7
.
%
在 C++ 中是一个余数运算符(对于正数,它用作数学模运算符)。
因为在大多数 C 实现中,整数除法会截断并且不会向负无穷大舍入。您的实现似乎也是其中之一。
a % b = a - (a / b) * b
所以
7 % (-5) = 7 - (7 / -5) * (-5)
这是
7 % (-5) = 7 - (-1) * (-5) = 7 - 5 = 2
在 C 90 或 C++ 98 标准中没有指定负数的模数应该是什么符号。任何一个都可以接受。它在 C 99 和 C++ 2011 中被定义为具有与被除数相同的符号。
有关模数和余数之间差异的讨论,请参阅这篇文章:
还有这篇维基百科上的文章,它引用了标准状态。
答案不是数学的,而是传统的。理论上,模运算符总是有两种可能的结果,负数和正数。
7 % 5
要么2
要么-3
。
在数学中,通常使用积极的结果。在取决于编程语言的编程中。
原始 C 没有指定使用哪一个。使用正数,您总是得到正模数;对于负数,结果取决于所使用的编译器。
C-99 指定模数的结果应该与被除数具有相同的符号。这解释了你观察到的行为。
您可以在此处查看不同编程语言的模运算符的结果。
规则是r = a - (a/b) * b
所以
2 = 7 - (7/-5)*(-5) // note: 7/-5 is -1
负值的模运算在 IT 中没有单一的定义。三种不同的算法:
当操作数为正时提供相同的结果,但在操作数为负时提供不同的结果。
许多实现使用截断除法,其中商由截断 q = trunc(a/n) 定义,换句话说,它是从精确有理商到 0 方向的第一个整数,余数为 r=a - n q . 非正式地讲,商“向零舍入”,因此余数与被除数具有相同的符号。
Knuth 描述了下限除法,其中商由下限函数 q=floor(a/n) 定义,余数 r 为
r = a - nq = a - n \left\lfloor {a \over n} \right\rfloor.
这里商总是向下舍入(即使它已经是负数),余数与除数的符号相同。
Raymond T. Boute 引入了欧几里得定义,即余数始终为正或 0 的定义,因此与除法算法一致(参见欧几里得除法)。这个定义在表中被标记为“总是积极的”。设 q 为 a 和 n 的整数商,则:
在 C 中,问题是算法是实现定义的,因此如果您希望程序可移植,则需要为负数滚动自己的模运算。