Python中负数的模运算
Posted
技术标签:
【中文标题】Python中负数的模运算【英文标题】:The modulo operation on negative numbers in Python 【发布时间】:2011-04-22 10:22:08 【问题描述】:我在 Python 中发现了一些关于负数的奇怪行为:
>>> -5 % 4
3
谁能解释一下是怎么回事?
【问题讨论】:
我觉得很合适..., -9, -5, -1, 3, 7, ...
C,Python - different behaviour of the modulo (%) operation的可能重复
您可以使用 math.fmod
获得与 C 或 Java 中相同的行为。
【参考方案1】:
与 C 或 C++ 不同,Python 的模运算符 (%
) 总是返回一个与分母(除数)符号相同的数字。你的表达式产生 3 因为
(-5) / 4 = -1.25 --> 楼层(-1.25) = -2
(-5) % 4 = (-2 × 4 + 3) % 4 = 3。
选择它而不是 C 行为,因为非负结果通常更有用。一个例子是计算工作日。如果今天是星期二(第 2 天),那么前 N 天是星期几?在 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,了解如何确定不同语言的结果符号。)
【讨论】:
令人惊讶的是,Python 的模运算符 (%) 不 总是 返回一个与分母(除数)符号相同的数字。见***.com/questions/48347515/…【参考方案2】:下面是 Guido van Rossum 的解释:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
本质上,a/b = q 与余数 r 保持关系 b*q + r = a 和 0
【讨论】:
像 C++ 和 Java 这样的语言也保留了第一个关系,但它们的上限为负数a
,正数b
,而 Python 楼层数。 abs(r) < b
总是正确的,如果 r <= 0
是他们的上限。【参考方案3】:
在 python 中,模运算符的工作方式如下。
>>> 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 中舍入的更多信息,请阅读this。
【讨论】:
【参考方案4】:正如所指出的,Python 取模对其他语言的约定产生了well-reasoned 例外。
这为负数提供了一种无缝的行为,尤其是与//
整数除法运算符结合使用时,因为%
模通常是(如在数学中。divmod):
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
Python %
始终输出零或正数*
Python //
总是向负无穷大舍入
* ...只要右操作数为正数。另一方面11 % -10 == -9
【讨论】:
谢谢你的例子让我明白了:)【参考方案5】:没有一种最好的方法来处理整数除法和带负数的 mods。如果a/b
与(-a)/b
的大小相同,符号相反,那就太好了。如果a % b
确实是模 b,那就太好了。由于我们真的想要a == (a/b)*b + a%b
,所以前两个是不兼容的。
保留哪一个是一个难题,双方都有争论。 C 和 C++ 将整数除法四舍五入到零(所以 a/b == -((-a)/b)
),显然 Python 没有。
【讨论】:
"如果 a/b 与 (-a)/b 的大小相同但符号相反,那就太好了。"为什么会很好?这是什么时候需要的行为? 因为它的行为方式与常规除法和乘法相同,因此直观上易于使用。不过,这在数学上可能没有意义。【参考方案6】:其他答案,尤其是选定的答案,已经很好地回答了这个问题。但我想介绍一种可能更容易理解的图形方法,以及在 python 中执行普通数学模的 python 代码。
傻瓜的 Python 模数
模函数是一个方向函数,它描述了在我们在无限数的 X 轴上进行除法过程中的数学跳跃之后,我们必须移动多少或向后移动多少。
所以假设你在做7%3
所以在前向,你的答案是+1,但在后向-
你的答案是-2。两者都是正确的数学上。
同样,负数也有 2 个模数。例如:-7%3
,可以导致 -1 或 +2,如图所示 -
前进方向
向后方向
在数学中,我们选择向内跳跃,即正数为正向,负数为反向。
但在 Python 中,我们对所有正模运算都有一个正向方向。因此,您的困惑-
>>> -5 % 4
3
>>> 5 % 4
1
这是python中向内跳转类型取模的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
很多人会反对内跳法,但我个人的看法是,这个更好!!
【讨论】:
感谢可视化,它真的很有帮助。想补充一下“但是在 Python 中,我们对所有模运算都有一个前进的方向。”。 7 % -3 或 7 % -3 怎么样?这不是倒退吗? @Alex 是的,你是对的,我的意思是“对于所有正模运算”。【参考方案7】:模数,4 的等价类:
0:0、4、8、12...和-4、-8、-12... 1:1、5、9、13... 和 -3、-7、-11... 2:2、6、10... 和 -2、-6、-10... 3:3、7、11... 和 -1、-5、-9...这是modulo's behavior with negative numbers 的链接。 (是的,我用谷歌搜索过)
【讨论】:
@NullUserException - 是的,确实如此。固定的。谢谢。 链接好像失效了 @Astariul 互联网的大问题。如果您有其他建议,我完全赞成。也就是说,这是一个 11 年前的帖子! 我不明白你的解释【参考方案8】:我还认为这是 Python 的一种奇怪行为。事实证明,我没有很好地解决除法问题(在纸上);我给商的值是 0,给余数的值是 -5。太可怕了...我忘记了整数的几何表示。通过回忆数轴给出的整数的几何形状,可以得到商和余数的正确值,并检查 Python 的行为是否正常。 (虽然我假设您很久以前就已经解决了您的问题)。
【讨论】:
【参考方案9】:还值得一提的是,python 中的除法也与 C 不同: 考虑
>>> x = -10
>>> y = 37
在 C 中你期望得到结果
0
python 中的 x/y 是什么?
>>> print x/y
-1
并且 % 是模数 - 不是余数!而 C 中的 x%y 产生
-10
python 产生。
>>> 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 中相同的结果,而且它避免了条件语句。
【讨论】:
【参考方案10】:你可以使用:
result = numpy.fmod(x,y)
它将保留标志,请参阅numpy fmod() documentation。
【讨论】:
以上是关于Python中负数的模运算的主要内容,如果未能解决你的问题,请参考以下文章