从C++和Python除法的区别谈谈求模(Modulus)和取余(Remainder)
今天发现一个很有意思的现象。
当做除法的时候,Python2和C++在负数的情况下会得到不同的整除结果:
当做-5 / 3的时候
C++的结果: -1
Python2的结果:-2
(请注意5 / -3的时候仍然会在C++中得到-1, Python2中得到-2)
可以看出C++在进行负数整除的时候执行的是直接舍去小数点后数字的操作,也就是返回和0比较接近的那个数字。
但在Python2中返回的则是小于等于商的最大整数,也就是返回和-∞更接近的数。
在做%操作的时候,依据的是这样的逻辑:
a = b * c + r
其中a是被除数,b是除数,c是商,r是%操作的结果。
在上述例子中,a和b是-5和3。
C++的情况下商c是-1,因此r可以算出来是-2。
Python情况下商c是-2,因此r可以算出来是1。
!!!值得注意的是:当把操作改成5 % -3的时候,C++的结果是2,Python2的结果是-1,和之前的结果正好符号相反。
如果有同学觉得这里非常乱,请牢记a = b * c + r。
用同样的逻辑,当a是5,b是-3时,c++因为商c是-1,因此r是2,Python时商c是-2因此r是-1。
那么造成这种差异的原因是什么呢?
其实是因为“求模”(Modulus)和“取余”(Remainder)的区别。
很多同学可能认为,求模运算和取余运算是一回事。实际上在正整数范围内它们确实表现出完全相同的性质。但在负数运算的情况下,它们则会表现出不同的行为。
C++的%表现出的是“取余”操作的结果。
Python的%表现出的是“求模”操作的结果。
无论C++还是Python,求模和取余都是根据a = b * c + r这个公式定义的,而唯一的区别就是商c究竟是向0方向取整还是向-∞方向取整。
当商c向0方向取整的时候,得到的r是“余数”,也就是在C++中的结果。
当商c向-∞方向取整的时候,得到的r是“模数”,也就是在Python2中的结果。
在Python3中,无论“/”两边是否均为整数,运算的时候都转换成实数运算并返回实数。整除则用“//”来表示。
利用Python这个整除的特性,我们可以得到一个小技巧:
很多时候我们会碰到“某物x个一组,一共需要y个,至少需要多少组?”这样的问题。
在C++中我们必须写成这样的逻辑:answer = y / x; if (y % x != 0) ans += 1;
在Python中我们可以利用负数的特性很方便地得到结果:answer = -(-y // x)。