为什么是数学。地板(x/y)!=Python中两个可等分浮点的x//y?
我一直在阅读Python中的除法和整数除法,以及Python2和Python3中除法的区别。在大多数情况下,这一切都是有道理的。Python 2仅当两个值都是整数时才使用整数除法。Python3总是执行真正的除法。Python 2.2+引入了整数除法的为什么是数学。地板(x/y)!=Python中两个可等分浮点的x//y?,python,division,integer-division,Python,Division,Integer Division,我一直在阅读Python中的除法和整数除法,以及Python2和Python3中除法的区别。在大多数情况下,这一切都是有道理的。Python 2仅当两个值都是整数时才使用整数除法。Python3总是执行真正的除法。Python 2.2+引入了整数除法的/运算符 其他程序员提供了一些很好且简洁的示例,例如: >>> 1.0 // 2.0 # floors result, returns float 0.0 >>> -1 // 2 # n
/
运算符
其他程序员提供了一些很好且简洁的示例,例如:
>>> 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.9999999999999999
和math.floor(4.9999999999999)==4.0
的地方存在浮点错误,这不会反映在x/y
中吗
但是,以下类似情况不受影响:
>>> (.5*10) // (.1*10)
5.0
>>> .1 // .1
1.0
那是因为
>>> .1
0.10000000000000001
.1
不能用二进制精确表示
你也可以看到
>>> .5 / 0.10000000000000001
5.0
问题是Python会将输出四舍五入为整数。由于
0.1
不能用二进制精确表示,因此结果类似于4.999999999999722444243844000
。当不使用格式时,这自然会变成5.0
其他答案我都不满意。当然,.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
首先,请注意,.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
是楼层(.5/.1)
的简写,但事实并非如此。事实证明,语义不同。尽管:
楼层划分将在所有区域实施
类型,并将具有
a // b == floor(a/b)
事实证明,.5//.1
的语义实际上相当于:
floor((.5 - mod(.5, .1)) / .1)
其中,mod
是.5/.1
的浮点余数向零舍入。这一点可以通过阅读文章来明确
这就是为什么.1
不能用二进制扩展精确表示的原因。.5/.1
的浮点余数为非零:
>>> .5 % .1
0.09999999999999998
事实并非如此,这是有道理的。由于.1
的二进制扩展比实际的十进制.1
稍大,因此最大的整数alpha
,因此alpha*.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.100000000000000551151231
那么当我们分开时会发生什么呢
>>> 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
并确认这确实是4.999999999999722444243845
为什么不直接做分数(.5/.1)
或分数(十进制(.5)/十进制(.1))
?
后者将为我们提供相同的5/1
结果。前者将为我们提供12499999999999930611060961/25000000000000000000000000
。这将导致4.999999999999972444243844
,类似但不相同的结果。@J.Money:try(0.1)。as_integer_ratio()
或格式(0.1,'1.30f')
这不应该是公认的答案。我猜从技术上来说,它回答了OP的问题,但没有解释。请使用以下链接更新您的答案,使其更加完整:,@searchengine27。1不能用二进制表示,这还不够解释吗?(另外,其他答案给出了不同层次的详细信息,user5248483发布了一个指向Python3浮动教程的链接,该教程在解释所有细节方面做得非常好)甚至没有接近。浮点数的公式在哪里?对事物实际如何表现的解释?说“那不行”并不等于说“这就是它的工作原理”。参考IEEE 754可能是一个开始,但你甚至没有努力做到这一点。说别人给出了正确的答案,并不能使你的答案正确。这使他们的答案正确,a
>>> print float((xa/xb)/(ya/yb)).as_integer_ratio()
(5, 1)
>>> print Fraction((xa/xb)/(ya/yb))
999999999999999944488848769/200000000000000000000000000