Python中负数的模运算

时间:2010-10-07 15:00:39

标签: python modulo negative-number

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

>>> -5 % 4
3

有人可以解释发生了什么吗?

9 个答案:

答案 0 :(得分:93)

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

  

( - 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。)

答案 1 :(得分:25)

以下是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&lt; = r&lt;湾

答案 2 :(得分:8)

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

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

答案 3 :(得分:5)

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 :(得分:4)

正如所指出的,Python模数对其他语言的约定提出了well-reasoned例外。

这为负数提供了无缝行为,尤其是与//整数除法运算符结合使用时,%模数通常是(如数学divmod中所示):< / p>

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 //始终向负无穷大方向转变

答案 5 :(得分:3)

Modulo,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的链接。 (是的,我用谷歌搜索了它)

答案 6 :(得分:1)

我还认为这是Python的奇怪行为。事实证明,我并没有很好地解决这个部门(在纸面上);我给商的值为0,剩下的值为-5。可怕......我忘记了整数数字的几何表示。通过调用数字行给出的整数几何,可以得到商和余数的正确值,并检查Python的行为是否正常。 (虽然我认为你很久以前就已经解决了你的问题。)

答案 7 :(得分:0)

值得一提的是,python中的除法也不同于C: 考虑

import csv

#loading Source CSV file and parse it into list of integer numbers
with open('Source.csv', 'r') as csvfile:
    scr_data_list = []
    for row in csv.reader(csvfile, delimiter=','):
        scr_data_list.append(row[0]) # careful here with [0]
csvfile.close()

#print scr_data_list
#print "\n"

temp_scr_list = []  # temp list to store 5 values from Source list
temp_des_list = []  # temp list to store 9 numbers drived from "temp_scr_list"
des_data_list = []   # Destination List contaning whole data
step = 5
i = 0
while i < len(scr_data_list):

    j = 0
    while j <5:
        temp_scr_list.append(float(scr_data_list[i+j]))
        j = j+1

    # Main logic of this program
    #print temp_scr_list

    temp_des_list.append(temp_scr_list[2]) # value at -20 offset
    temp_des_list.append(temp_scr_list[2]+0.05) # value at -14 offset (derived)
    temp_des_list.append(temp_scr_list[1]-0.2) # value at -10 offset (derived)
    temp_des_list.append(temp_scr_list[1]) # value at -5 offset

    temp_des_list.append(temp_scr_list[0]) # value at 0 offset

    temp_des_list.append(temp_scr_list[3]) # value at 5 offset
    temp_des_list.append(temp_scr_list[3]-0.2) # value at 10 offset (derived)
    temp_des_list.append(temp_scr_list[4]+0.05) # value at 14 offset (derived)
    temp_des_list.append(temp_scr_list[4]) # value at 20 offset

    des_data_list.extend(temp_des_list)

    # step 5 values forward
    i=i+5


    # clear the lists
    temp_scr_list = []
    temp_des_list = []  

print len(des_data_list)


# write the numbers from "des_data_list" list to a CSV file
with open('Destination.csv', 'wb') as writeFile:
    for r in des_data_list:
        writeFile.write(str(r) + "\n")


writeFile.close()

在C语言中,您期望得到结果

>>> x = -10
>>> y = 37

python中的x / y是什么?

0

和%是模数-不是余数! C的x%y会产生

>>> print x/y
-1

python产量。

-10

您可以像在C中一样获得两者

部门:

>>> print x%y
27

其余的(使用上面的除法):

>>> from math import trunc
>>> d = trunc(float(x)/y)
>>> print d
0

这种计算可能不是最快的,但是它适用于x和y的任何符号组合,以达到与C中相同的结果,并且避免了条件语句。

答案 8 :(得分:0)

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

傻瓜的 Python 模数

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

enter image description here

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

enter image description here

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

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

enter image description here

前进方向


enter image description here

向后方向


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

但在 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

很多人会反对内跳法,但我个人的看法是,这个更好!!