具有负值的模运算符

scd*_*dmb 156 c++

为什么这样的操作:

std::cout << (-7 % 3) << std::endl;
std::cout << (7 % -3) << std::endl;
Run Code Online (Sandbox Code Playgroud)

给出不同的结果?

-1
1
Run Code Online (Sandbox Code Playgroud)

Pla*_*aHH 187

来自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
Run Code Online (Sandbox Code Playgroud)

注意

如果两个操作数都是非负的,那么余数是非负的; 如果没有,余数的符号是​​实现定义的.

ISO14882:2003(e)中不再出现ISO14882:2011(e)

  • @JamesKanze:C++ 03仍然包含实现定义,它是C++ 11删除它.(并且要求部门遵循fortran,基本上) (7认同)
  • @KerrekSB现在在C++ 11中定义. (5认同)
  • 我认为不管你用哪种方式和多少次皮肤,基本的事实是带有签名操作数的除法和模数是实现定义的.在某种形式或其他方面总是有"哪种方式"的选择.该报价末尾的保证身份是重要的.(虽然我认为C99实际上可以解决这个问题.) (4认同)
  • @Buge:C++11 基于 C99,所以这是有道理的。 (2认同)

Naw*_*waz 19

这种情况下的符号(即当一个或两个操作数为负时)是实现定义的.该规范在§5.6/ 4(C++ 03)中说,

二元/运算符产生商,二元%运算符从第一个表达式除以第二个表达式得到余数.如果/或%的第二个操作数为零,则行为未定义; 否则(a/b)*b + a%b等于a.如果两个操作数都是非负的,那么余数是非负的; 如果没有,余数的符号是​​实现定义的.

就C++ 03而言,这就是所有语言所必须说的.

  • 这就是**所说的所有语言.C++ 11(如C99)采用Fortran舍入为零的规则(即丢弃小数部分).实际上,很久以前所有的硬件都采用了Fortran规则,所以所有的实现都已经这样做了.("实现定义"的目的是允许C/C++做任何硬件所做的事情.我认为一些非常旧的硬件总是向下舍入,所以`-7/3`会导致`-3`,但那将是一个遥远的过去.) (14认同)
  • @JamesKanze:在优化二次幂分割作为移位的情况下,现有硬件的行为是*NOT*.根据旧规则,`foo/= 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`]不像分割指令那么慢,但比简单的转换要多得多. (3认同)
  • @CptRobby 你似乎忘记了 C 的整个设计理念都是围绕着 hacky 快捷方式来生成更快的汇编代码。 (3认同)
  • @JamesKanze:如果“b”是 2 的幂,则过去可以将“n % b”计算为“n &amp; (b-1)”。新标准要求计算为“n &lt; 0 ? n | -b:n &amp; (b-1)`。同样,即使在支持算术移位的硬件上,“n / b”也不能写成简单的移位;相反,在此类系统上,像“n/16”这样的表达式(如果“n”是“int32”)必须写为“n &lt; 0”?(n+15) &gt;&gt; 4 : n &gt;&gt; 4`。可怕的标准,恕我直言。请注意,由于非二的幂除法本质上很慢,因此强制执行欧几里得行为不会使其减慢太多。 (2认同)
  • @supercat抱怨人类可读语言中的算术函数的工作方式,因为必须在机器代码中执行多少指令才能保持一致,而不是使用只用所有可能值的一小部分简化操作的hacky快捷方式?哇.哇哇.*慢拍* (2认同)

Kto*_* To 19

a % b
Run Code Online (Sandbox Code Playgroud)

在c ++中默认:

(-7/3) => -2
-2 * 3 => -6
so a%b => -1

(7/-3) => -2
-2 * -3 => 6
so a%b => 1
Run Code Online (Sandbox Code Playgroud)

在python中:

-7 % 3 => 2
7 % -3 => -2
Run Code Online (Sandbox Code Playgroud)

在c ++到python中:

(b + (a%b)) % b
Run Code Online (Sandbox Code Playgroud)

  • 在负数的情况下,没有关于结果符号的“ C ++默认值”。 (3认同)