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) &lt; b 总是正确的,如果 r &lt;= 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中负数的模运算的主要内容,如果未能解决你的问题,请参考以下文章

c语言,求一个数的逆的模n运算等于多少!

python python中的模运算

C中按位运算的模运算

使用带浮点数的模运算符

c 整数运算

大数相乘求和的模运算