我在Python中发现了一些关于负数的奇怪行为:
>>> -5 % 4
3
有人可以解释发生了什么吗?
答案 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
%
总是输出零或正数//
始终向负无穷大方向转变答案 5 :(得分:3)
Modulo,4的等价类:
这是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
所以在向前的方向,你的答案是 +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
很多人会反对内跳法,但我个人的看法是,这个更好!!