为什么会出现以下这种操作:
std::cout << (-7 % 3) << std::endl;
std::cout << (7 % -3) << std::endl;
会给出不同的结果吗?
-1
1
为什么会出现以下这种操作:
std::cout << (-7 % 3) << std::endl;
std::cout << (7 % -3) << std::endl;
会给出不同的结果吗?
-1
1
来自ISO14882:2011(e) 5.6-4:
二元运算符/生成商,二元运算符%生成第一个表达式除以第二个表达式的余数。如果/或%的第二个操作数为零,则行为未定义。 对于整型操作数,/运算符产生代数商,丢弃任何小数部分; 如果商a/b表示为结果类型,则(a/b)* b + a%b等于a。
其余是基本数学:
(-7 / 3) => -2
-2 * 3 => -6
so a % b => -1
(7 / -3) => -2
-2 * -3 => 6
so a % b => 1
请注意:
如果两个操作数都是非负数,则余数为非负数;如果不是,则余数的符号是实现定义的。
ISO14882:2003(e)中的内容在ISO14882:2011(e)中已经不存在了。
a % b
C++中的默认情况:
(-7 / 3) => -2
-2 * 3 => -6
so a % b => -1
(7 / -3) => -2
-2 * -3 => 6
so a % b => 1
在Python中:
-7 % 3 => 2
7 % -3 => -2
在C++中转换为Python:
(b + (a % b)) % b
就C ++ 03而言,这就是所有语言所要说的了。二进制运算符/产生商,二进制运算符%产生第一个表达式除以第二个表达式的余数。如果/或%的第二个操作数为零,则行为未定义;否则(a/b)*b+a%b等于a。如果两个操作数都为非负数,则余数为非负数; 如果不是,则余数的符号是实现定义的。
-7/3
将得到-3
,但那已经是遥远的过去了。) - James Kanzeb
是2的幂,以前可以通过n % b
计算为n & (b-1)
。新标准要求将其计算为n < 0 ? n | -b : n & (b-1)
。同样地,即使在支持算术移位的硬件上,n / b
也不能简单地写成一个移位操作;在这种系统上,像n/16
(如果n
是int32
)这样的表达式必须写成n < 0 ? (n+15) >> 4 : n >> 4
。我个人认为这个标准很糟糕。请注意,由于非2的幂除法本身就很慢,强制使用欧几里得行为并不会使其变慢太多。 - supercatfoo /= 16
可以写成 asr [dword foo],4
。但根据新规则,最优表示需要更多指令[可能是 mov eax,[foo] / mov ebx,eax, asr eax,31 / lsr eax,28 / add eax,ebx / asr eax,4 / mov [foo],eax
]。虽然不像除法指令那么慢,但比简单的移位要更加复杂繁琐。 - supercat
-7/3
的结果是-2
还是-3
)。 - James Kanze