我一直在阅读Python中的除法和整数除法以及Python2与Python3之间的区别。在大多数情况下,这一切都是有道理的。仅当两个值都是整数时,Python 2才使用整数除法。 Python 3总是执行真正的划分。 Python 2.2+为整数除法引入了//
运算符。
其他程序员提供的实例很好,很整洁,例如:
>>> 1.0 // 2.0 # floors result, returns float
0.0
>>> -1 // 2 # negatives are still floored
-1
//
如何实施?为什么会发生以下情况:
>>> import math
>>> x = 0.5
>>> y = 0.1
>>> x / y
5.0
>>> math.floor(x/y)
5.0
>>> x // y
4.0
不应该x // y = math.floor(x/y)
?这些结果是在python2.7上生成的,但由于x和y都是浮点数,因此python3 +上的结果应该相同。如果存在某些浮点错误,其中x/y
实际为4.999999999999999
且math.floor(4.999999999999999) == 4.0
不会反映在x/y
中?
但是,以下类似案例不受影响:
>>> (.5*10) // (.1*10)
5.0
>>> .1 // .1
1.0
答案 0 :(得分:24)
我没有找到满意的其他答案。当然,.1
没有有限的二进制扩展,所以我们的预感是表示错误是罪魁祸首。但是这种预感并不能解释为什么math.floor(.5/.1)
会产生5.0
而.5 // .1
会产生4.0
。
一句话是,a // b
实际正在做floor((a - (a % b))/b)
,而不是floor(a/b)
。
首先,请注意,.5 / .1
的结果在Python中完全 5.0
。即使.1
无法准确表示,情况也是如此。拿这个代码,例如:
from decimal import Decimal
num = Decimal(.5)
den = Decimal(.1)
res = Decimal(.5/.1)
print('num: ', num)
print('den: ', den)
print('res: ', res)
和相应的输出:
num: 0.5
den: 0.1000000000000000055511151231257827021181583404541015625
res: 5
这表明.5
可以用有限的二进制扩展来表示,但.1
不能。但它也表明,尽管如此,.5 / .1
的结果正是5.0
。这是因为浮点除法导致精度损失,den
与.1
的差异在此过程中丢失。
这就是为什么math.floor(.5 / .1)
可以正常工作的原因:因为.5 / .1
是 5.0
,所以写math.floor(.5 / .1)
就是一样的写作math.floor(5.0)
。
.5 // .1
导致5?有人可能会认为.5 // .1
是floor(.5 / .1)
的简写,但事实并非如此。事实证明,语义不同。这是PEP says:
分区将在所有Python数字中实现 类型,并将具有
的语义a // b == floor(a/b)
事实证明,.5 // .1
的语义实际等同于:
floor((.5 - mod(.5, .1)) / .1)
其中mod
是.5 / .1
的浮点余数向零舍入。通过阅读Python source code来明确这一点。
此是.1
无法通过二进制扩展准确表示的事实导致问题。 .5 / .1
的浮点余数为不零:
>>> .5 % .1
0.09999999999999998
它是不合理的。由于.1
的二进制扩展比实际的小数.1
略大,所以最大的整数alpha
使得alpha * .1 <= .5
(在我们的有限精度数学中)是alpha = 4
。因此mod(.5, .1)
非零,大致为.1
。因此,floor((.5 - mod(.5, .1)) / .1)
变为floor((.5 - .1) / .1)
变为floor(.4 / .1)
,等于4
。
这就是.5 // .1 == 4
。
//
会这样做? a // b
的行为可能看起来很奇怪,但这是math.floor(a/b)
与[{1}}分歧的原因。在他关于Python历史的blog中,Guido写道:
整数除法运算(//)及其兄弟,模数 操作(%),一起去满足一个很好的数学 关系(所有变量都是整数):
a/b = q with remainder r
这样
b*q + r = a and 0 <= r < b
(假设a和b> = 0)。
现在,Guido假设所有变量都是整数,但如果a
和b
是浮点数,那么这种关系仍将成立,如果 q = a // b
。如果q = math.floor(a/b)
关系赢得一般保留。所以//
可能是首选,因为它满足了这种良好的数学关系。
答案 1 :(得分:6)
那是因为
>>> .1
0.10000000000000001
.1
无法用二进制
您还可以看到
>>> .5 / 0.10000000000000001
5.0
答案 2 :(得分:2)
问题是Python会将输出四舍五入为described here。由于0.1
无法用二进制表示,因此结果类似于4.999999999999999722444243844000
。当然,当不使用格式时,这变为5.0
。
答案 3 :(得分:-1)
这是不正确的,我害怕。 .5 / .1完全是5.0。见:(。5 / .1).as_integer_ratio(),得到(5,1)。
是的,5
可以表示为5/1
,这是真的。但是为了看到Python由于不精确的表示而给出的实际结果的分数,请继续。
首先,导入:
from decimal import *
from fractions import Fraction
易于使用的变量:
// as_integer_ratio() returns a tuple
xa = Decimal((.5).as_integer_ratio()[0])
xb = Decimal((.5).as_integer_ratio()[1])
ya = Decimal((.1).as_integer_ratio()[0])
yb = Decimal((.1).as_integer_ratio()[1])
产生以下数值:
xa = 1
xb = 2
ya = 3602879701896397
yb = 36028797018963968
当然,1/2 == 5
和3602879701896397 / 36028797018963968 == 0.1000000000000000055511151231
。
那么当我们分裂时会发生什么?
>>> print (xa/xb)/(ya/yb)
4.999999999999999722444243845
但是当我们想要整数比...
>>> print float((xa/xb)/(ya/yb)).as_integer_ratio()
(5, 1)
如前所述,5
当然是5/1
。这就是Fraction
的来源:
>>> print Fraction((xa/xb)/(ya/yb))
999999999999999944488848769/200000000000000000000000000
wolfram alpha确认这确实是4.999999999999999722444243845
。
为什么不执行Fraction(.5/.1)
或Fraction(Decimal(.5)/Decimal(.1))
?
后者会给我们相同的5/1
结果。前者会给我们1249999999999999930611060961/250000000000000000000000000
。这导致4.999999999999999722444243844
,类似但不一样的结果。