J.M*_*ney 23 python division integer-division
我一直在阅读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
Run Code Online (Sandbox Code Playgroud)
如何//实施?为什么会发生以下情况:
>>> import math
>>> x = 0.5
>>> y = 0.1
>>> x / y
5.0
>>> math.floor(x/y)
5.0
>>> x // y
4.0
Run Code Online (Sandbox Code Playgroud)
不应该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
Run Code Online (Sandbox Code Playgroud)
jme*_*jme 24
我没有找到满意的其他答案.当然,.1没有有限的二进制扩展,所以我们的预感是表示错误是罪魁祸首.但这种预感并不能真正解释为什么math.floor(.5/.1)收益率5.0和.5 // .1收益率4.0.
与简单相反,实际上a // b就是这样做的妙语.floor((a - (a % b))/b)floor(a/b)
首先,请注意,结果.5 / .1是正好 5.0在Python.即使.1无法准确表示,情况也是如此.以此代码为例:
from decimal import Decimal
num = Decimal(.5)
den = Decimal(.1)
res = Decimal(.5/.1)
print('num: ', num)
print('den: ', den)
print('res: ', res)
Run Code Online (Sandbox Code Playgroud)
和相应的输出:
num: 0.5
den: 0.1000000000000000055511151231257827021181583404541015625
res: 5
Run Code Online (Sandbox Code Playgroud)
这表明.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说:
分区将在所有Python数字类型中实现,并具有语义
Run Code Online (Sandbox Code Playgroud)a // b == floor(a/b)
事实证明,语义.5 // .1是实际上等同于:
floor((.5 - mod(.5, .1)) / .1)
Run Code Online (Sandbox Code Playgroud)
其中mod浮点余数.5 / .1向零舍入.通过阅读Python源代码可以清楚地看到这一点.
这是.1二进制扩展无法准确表示的事实导致问题.的浮点余数.5 / .1是不是零:
>>> .5 % .1
0.09999999999999998
Run Code Online (Sandbox Code Playgroud)
而事实并非如此.由于二元扩张.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).在他关于Python历史的博客中,Guido写道:
整数除法运算(//)及其兄弟,模运算(%),一起使用并满足一个很好的数学关系(所有变量都是整数):
Run Code Online (Sandbox Code Playgroud)a/b = q with remainder r这样的
Run Code Online (Sandbox Code Playgroud)b*q + r = a and 0 <= r < b(假设a和b> = 0).
现在,圭多假定所有变量均为整数,但这种关系将仍然坚持,如果a和b是花车,如果 q = a // b.如果q = math.floor(a/b)这种关系一般不会成立.因此它//可能是首选,因为它满足了这种良好的数学关系.
那是因为
>>> .1
0.10000000000000001
Run Code Online (Sandbox Code Playgroud)
.1 无法用二进制精确表示
你也可以看到
>>> .5 / 0.10000000000000001
5.0
Run Code Online (Sandbox Code Playgroud)