Python中负数的模运算

fac*_*cha 64 python modulo negative-number

我在Python中发现了一些关于负数的奇怪行为:

>>> -5 % 4
3
Run Code Online (Sandbox Code Playgroud)

谁能解释一下发生了什么?

ken*_*ytm 103

与C或C++不同,Python的模运算符(%)总是返回一个与分母(除数)具有相同符号的数字.你的表达式得到3因为

(-5)%4 =( - 2×4 + 3)%4 = 3.

它是根据C行为选择的,因为非负结果通常更有用.一个例子是计算工作日.如果今天是星期二(第2天),那么N天前的星期几是多少?在Python中我们可以使用

return (2 - N) % 7
Run Code Online (Sandbox Code Playgroud)

但在C中,如果Ñ ≥3,我们得到一个负数,其是无效的号码,我们需要通过添加7手动修复它:

int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
Run Code Online (Sandbox Code Playgroud)

(有关如何确定不同语言的结果符号,请参见http://en.wikipedia.org/wiki/Modulo_operator.)

  • 令人惊讶的是,Python的模运算符(%)**不会***总是*返回一个与分母(除数)具有相同符号的数字.请参阅/sf/ask/3384326081/ (4认同)
  • @kuzzooroo 是的,“Decimal”和“int”对象之间的行为是不同的,正如您在链接到的问题中看到的那样。 (2认同)

Dee*_*ant 28

其他答案,尤其是所选答案,已经很好地清楚地回答了这个问题。但我想提出一种可能更容易理解的图形方法,以及在 python 中执行正常数学模数的 python 代码。

Python 取模傻瓜书

模函数是一种方向函数,它描述了在对无限数的 X 轴进行除法过程中进行数学跳跃后,我们必须向前或向后移动多少距离。假设你正在做7%3

在此输入图像描述

所以在向前方向上,你的答案将是+1,但在向后方向上 -

在此输入图像描述

你的答案是-2。两者在数学上都是正确的。

同样,负数也有 2 个模数。例如:-7%3,可以导致 -1 或 +2,如下所示 -

在此输入图像描述

前进方向


在此输入图像描述

向后方向


在数学中,我们选择向内跳跃,即正数为向前方向,负数为向后方向。

但在 Python 中,我们对所有正模运算都有一个前进方向。因此,你的困惑 -

>>> -5 % 4 
3

>>> 5 % 4
1
Run Code Online (Sandbox Code Playgroud)

以下是 python 中向内跳转类型取模的 python 代码:

def newMod(a,b):
    res = a%b
    return res if not res else res-b if a<0 else res
Run Code Online (Sandbox Code Playgroud)

这会给 -

>>> newMod(-5,4)
-1

>>> newMod(5,4)
1
Run Code Online (Sandbox Code Playgroud)

很多人会反对向内跳的方法,但我个人的意见是,这个更好!


Kev*_*vin 26

以下是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 <= r <b.

  • 像C++和Java这样的语言也保留了第一种关系,但是它们是负面的"a",正面的"b",而是Python底层.`abs(r)<b`总是如此,如果`r <= 0`则它们就是ceil. (3认同)

Bob*_*ein 9

正如所指出的,Python modulo为其他语言的约定提供了一个合理的例外。

这为负数提供了无缝行为,尤其是与//整数除法运算符结合使用时,因为%模通常是(如在math.divmod 中):

for n in range(-8,8):
    print n, n//4, n%4
Run Code Online (Sandbox Code Playgroud)

产生:

 -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
Run Code Online (Sandbox Code Playgroud)
  • Python%总是输出零或正数*
  • Python//总是向负无穷大舍入

* ... 只要正确的操作数为正数。另一方面11 % -10 == -9


Mun*_*tur 9

python 中,模运算符的工作方式是这样的。

>>> mod = n - math.floor(n/base) * base
Run Code Online (Sandbox Code Playgroud)

所以结果是(对于你的情况):

mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3
Run Code Online (Sandbox Code Playgroud)

而其他语言如C、JAVA、JavaScript使用截断而不是地板。

>>> mod = n - int(n/base) * base
Run Code Online (Sandbox Code Playgroud)

这导致:

mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1
Run Code Online (Sandbox Code Playgroud)

如果您需要有关 Python 舍入的更多信息,请阅读


Dav*_*ley 8

没有一种最好的方法来处理带有负数的整数除法和mods.如果a/b是相同的幅度和相反的符号将是很好的(-a)/b.如果a % b确实是模数b 那将是很好的.因为我们真的想要a == (a/b)*b + a%b,前两个是不兼容的.

要保留哪一个是一个棘手的问题,双方都有争论.C和C++将整数除以零(so a/b == -((-a)/b)),显然Python没有.