整数除法是否总是等于常规除法的下限?

时间:2018-12-21 22:44:43

标签: python integer division floating-accuracy integer-division

对于大商来说,整数除法(//)不一定等于规则除法的底数(math.floor(a/b))。

根据Python文档(https://docs.python.org/3/reference/expressions.html-6.7),

  

整数的整数除法得到一个整数;结果是对数学结果进行了除法,并将“ floor”函数应用于结果。

但是,

math.floor(648705536316023400 / 7) = 92672219473717632

648705536316023400 // 7 = 92672219473717628

'{0:.10f}'.format(648705536316023400 / 7)的结果为'92672219473717617632.0000000000',但小数点后两位应该是28,而不是32。

4 个答案:

答案 0 :(得分:30)

您的测试用例中的商不同的原因是,在math.floor(a/b)情况下,结果是使用浮点算术(IEEE-754 64位)计算的,这意味着有最高的精度。您的商数大于2 53 的限制,超过该限制后,浮点数将不再精确到单位。

但是,通过整数除法,Python使用了其无限的整数范围,因此结果是正确的。

另请参阅"Semantics of True Division" in PEP 238

  

请注意,对于int和long参数,真正的除法可能会丢失信息;这是真正划分的性质(只要理性不在语言中)。有意识地使用long的算法应考虑使用//,因为long的真正除法最多可保留53位精度(在大多数平台上)。

答案 1 :(得分:18)

您可能正在处理的整数值太大而无法精确表示为浮点数。您的电话号码明显大于2 ^ 53,即where the gaps between adjacent floating point doubles start to get bigger than 1。因此,进行浮点除法时会失去一些精度。

另一方面,整数除法是精确计算的。

答案 2 :(得分:9)

您的问题是,尽管有时有时将“ /”称为“真除法运算符”,并且其方法名称为__truediv__,但其对整数的行为不是“真数学除法”。取而代之的是,它产生的浮点结果不可避免地具有有限的精度。

对于足够大的数字,即使数字的整数部分也可能会遇到浮点舍入误差。将648705536316023400转换为Python浮点数(IEEE两倍)时,会将其舍入为648705536316023424 1

我似乎找不到关于当前Python内置类型上的运算符确切行为的权威文档。引入该功能的原始PEP声明“ /”等效于将整数转换为浮点,然后执行浮点除法。但是,在Python 3.5中进行的快速测试表明情况并非如此。如果是这样,则以下代码将不会产生任何输出。

for i in range(648705536316023400,648705536316123400):
    if math.floor(i/7) != math.floor(float(i)/7):
        print(i)

但至少对我而言,它确实会产生输出。

在我看来,Python似乎正在对所给出的数字进行除法,并将结果四舍五入以适合浮点数。以该程序输出为例。

648705536316123383 // 7                   == 92672219473731911
math.floor(648705536316123383 / 7)        == 92672219473731904
math.floor(float(648705536316123383) / 7) == 92672219473731920
int(float(92672219473731911))             == 92672219473731904

Python标准库确实提供了分数类型,并且分数被整数除的除法运算符确实执行了“真正的数学除法”。

math.floor(Fraction(648705536316023400) / 7) == 92672219473717628
math.floor(Fraction(648705536316123383) / 7) == 92672219473731911

但是,您应该意识到使用Fraction类型可能会严重影响性能和内存。请记住,分数可以增加存储需求,而幅度不会增加。


为进一步检验“一舍入与二舍入”的理论,我用以下代码进行了检验。

#!/usr/bin/python3
from fractions import Fraction
edt = 0
eft = 0
base = 1000000000010000000000
top = base + 1000000
for i in range(base,top):
    ex = (Fraction(i)/7)
    di = (i/7)
    fl = (float(i)/7)
    ed = abs(ex-Fraction(di))
    ef = abs(ex-Fraction(fl))
    edt += ed
    eft += ef
print(edt/10000000000)
print(eft/10000000000)

与直接转换为浮点运算相比,直接进行除法运算的平均误差幅度要小得多,从而支持一舍入与二进位理论。

1 请注意,直接打印浮点数不会显示其确切值,而是显示将舍入到该值的最短十进制数(允许从浮点数到字符串再返回无损往返转换)浮动)。

答案 3 :(得分:0)

通过“数学除法”,Python文档表示实数上的 exact 除法。

现在,回到关于整数除法(又称欧几里得除法)与浮点除法(比“常规除法”更好的术语)的底数的问题,我在2005年研究了这个问题。最接近基数2的整数,如果x-y可以精确表示,则浮点除法x / y的下限(即math.floor(x/y))等于整数除法。您可以获取论文on my web siteon HAL