我在 Python 中发现了一些关于负数的奇怪行为:
>>> -5 % 4 3
有人能解释一下这是怎么回事吗?
与 C 或 C + + 不同,Python 的模运算符(%)总是返回与分母(除数)具有相同符号的数字。你的表达式得出3因为
%
(-5)/4 = -1.25—— > 楼层(-1.25) = -2 (-5)% 4 = (-2 × 4 + 3)% 4 = 3.
(-5)/4 = -1.25—— > 楼层(-1.25) = -2
(-5)% 4 = (-2 × 4 + 3)% 4 = 3.
它之所以选择 C 行为,是因为非负结果通常更有用。一个例子是计算工作日。如果今天是星期二(第二天) ,那么前几天是星期几?在 Python 中,我们可以使用
return (2 - N) % 7
但是在 C 中,如果 N≥3,我们得到一个负数,这是一个无效的数,我们需要手动修正它,加上7:
int result = (2 - N) % 7; return result < 0 ? result + 7 : result;
(如何确定不同语言的结果符号,请参阅 http://en.wikipedia.org/wiki/Modulo_operator。)
下面是吉多·范罗苏姆的一个解释:
Http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
本质上,a/b = q 余数 r 保持 b * q + r = a 和0 < = r < b 的关系。
模数,4的等价类:
这里有一个到 负数模的行为的链接。(是的,我谷歌了一下)
没有一种最好的方法来处理整数除法和带有负数的 mod。如果 a/b与 (-a)/b的大小相同,符号相反,那就太好了。如果 a % b确实是模 b 就好了。因为我们真正想要的是 a == (a/b)*b + a%b,所以前两个是不兼容的。
a/b
(-a)/b
a % b
a == (a/b)*b + a%b
保留哪一个是一个困难的问题,双方都有争议。C 和 C + + 将整数除法向零(所以是 a/b == -((-a)/b)) ,很明显 Python 没有这样做。
a/b == -((-a)/b)
正如前面所指出的,Python 模块对其他语言的约定造成了 理由充分异常。
这使得负数具有无缝的行为,特别是当与 //整数除法运算符结合使用时,就像 %模通常所做的那样(如在 math.迪莫德中) :
//
for n in range(-8,8): print n, n//4, n%4
制作:
-8 -2 0 -7 -2 1 -6 -2 2 -5 -2 3 -4 -1 0 -3 -1 1 -2 -1 2 -1 -1 3 0 0 0 1 0 1 2 0 2 3 0 3 4 1 0 5 1 1 6 1 2 7 1 3
* ... 只要正操作数是正的,另一方面 11 % -10 == -9
11 % -10 == -9
我还认为这是巨蟒的一种奇怪行为。事实证明,我没有很好地解决除法问题(在纸上) ; 我给商的值是0,给余数的值是 -5。糟糕... 我忘了整数的几何表示法。通过回想数字行给出的整数的几何形状,可以得到商和余数的正确值,并检查 Python 的行为是否正常。(尽管我认为你很久以前就已经解决了你的问题)。
同样值得一提的是,python 中的除法也不同于 C: 考虑一下
>>> x = -10 >>> y = 37
在 C 中,你期望得到结果
0
Python 中的 x/y 是多少?
>>> print x/y -1
而% 是模的-不是余数! 而 x% y 在 C 中的收益
-10
蟒蛇的产量。
>>> print x%y 27
你可以得到 C 中的两个
分工:
>>> from math import trunc >>> d = trunc(float(x)/y) >>> print d 0
其余部分(使用上面的除法) :
>>> r = x - d*y >>> print r -10
这个计算可能不是最快的,但是对于任何 x 和 y 的符号组合来说,都可以得到与 C 相同的结果,而且避免了条件语句。
在 巨蟒中,模运算符是这样工作的。
>>> mod = n - math.floor(n/base) * base
所以结果是(就你而言) :
mod = -5 - floor(-1.25) * 4 mod = -5 - (-2*4) mod = 3
而其他语言,如 C,JAVA,JavaScript,则使用截断代替地板。
>>> mod = n - int(n/base) * base
结果是:
mod = -5 - int(-1.25) * 4 mod = -5 - (-1*4) mod = -1
如果需要更多关于 python 舍入的信息,请阅读 这个。
其他的答案,特别是被选中的那个,已经很清楚地回答了这个问题。但是我想介绍一种图形化的方法,这种方法也可能更容易理解,同时还有在 python 中执行常规数学模块的 python 代码。
傻瓜用的 Python 模块
模函数是一个方向函数,它描述了在数学跳跃之后,我们需要向前或向后移动多少,这些跳跃是在 X 轴上的无限数字除法过程中产生的。 假设你在做 7%3
7%3
所以在向前的方向上,你的答案是 + 1,但是在向后的方向上-
你的答案是 -2,两个都是正确的 数学上来说。
类似地,对于负数也有2个模。对于例如: -7%3,可以导致 -1或 + 2,如图所示-
-7%3
前进方向
后退
在数学中,我们选择向内跳跃,即正数向前跳跃,负数向后跳跃。
但是在 Python 中,我们对所有的正模操作都有一个前进的方向
>>> -5 % 4 3 >>> 5 % 4 1
下面是 python 中向内跳转类型 module 的 python 代码:
def newMod(a,b): res = a%b return res if not res else res-b if a<0 else res
这会给
>>> newMod(-5,4) -1 >>> newMod(5,4) 1
很多人会反对向内跳的方法,但我个人的意见是,这个更好! !
你可使用:
result = numpy.fmod(x,y)
它将保持标志,见 Numpy fmod ()文档。
@ Deekshant 用可视化很好地解释了它。另一种理解% (模)的方法是问一个简单的问题。
在 X 轴上可以被除数整除的距离被除数最近的小数是多少?
让我们来看几个例子。
5 % 3
5是红利3是除数。如果你问上面的问题3是最小的可被除数整除的数。也就是5-3 = 2。对于正红利,最小数总是在红利的右边。
-5 % 3
可被3整除的最小数是 -6,因此 ans 是 -5-(-6) = 1
-5 %4
可被4整除的最小数是 -8,所以 ans 是 -5-(- 8) = 3
Python 用这种方法回答每一个模表达式。希望您能够理解接下来表达式将如何执行。
这就是模数的用途。如果你通过一系列数字做一个模,它会给出一个值的循环,比如:
ans = num % 3