简体   繁体   English

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

[英]Is integer division always equal to the floor of regular division?

For large quotients, integer division ( // ) doesn't seem to be necessarily equal to the floor of regular division ( math.floor(a/b) ).对于大商,整数除法 ( // ) 似乎不一定等于常规除法的下限 ( math.floor(a/b) )。

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

floor division of integers results in an integer;整数的地板除法产生一个整数; the result is that of mathematical division with the 'floor' function applied to the result.结果是将“floor”函数应用于结果的数学除法。

However,然而,

math.floor(648705536316023400 / 7) = 92672219473717632

648705536316023400 // 7 = 92672219473717628

'{0:.10f}'.format(648705536316023400 / 7) yields '92672219473717632.0000000000', but the last two digits of the decimal part should be 28 and not 32. '{0:.10f}'.format(648705536316023400 / 7)产生 '92672219473717632.0000000000',但小数部分的最后两位应该是 28 而不是 32。

The reason the quotients in your test case are not equal is that in the math.floor(a/b) case, the result is calculated with floating point arithmetic (IEEE-754 64-bit), which means there is a maximum precision. 测试用例中的商不相等的原因是在math.floor(a/b)情况下,结果是使用浮点运算(IEEE-754 64位)计算的,这意味着存在最大精度。 The quotient you have there is larger than the 2 53 limit above which floating point is no longer accurate up to the unit. 你在那里的商大于2 53的限制,高于该限制浮点不再精确到单位。

With the integer division however, Python uses its unlimited integer range, and so that result is correct. 但是,使用整数除法,Python使用其无限的整数范围,因此结果是正确的。

See also "Semantics of True Division" in PEP 238 : 另见PEP 238中的“真正划分的语义”

Note that for int and long arguments, true division may lose information; 请注意,对于int和long参数,真正的除法可能会丢失信息; this is in the nature of true division (as long as rationals are not in the language). 这是真正分裂的本质(只要理性不在语言中)。 Algorithms that consciously use longs should consider using // , as true division of longs retains no more than 53 bits of precision (on most platforms). 有意识地使用long的算法应该考虑使用// ,因为long的真正除法保留不超过53位的精度(在大多数平台上)。

You may be dealing with integral values that are too large to express exactly as floats. 您可能正在处理太大而不能完全表示为浮点数的整数值。 Your number is significantly larger than 2^53, which is where the gaps between adjacent floating point doubles start to get bigger than 1 . 您的数字明显大于2 ^ 53,这是相邻浮点数双精度之间的间隙开始大于1的位置 So you lose some precision when doing the floating point division. 因此,在进行浮点除法时会失去一些精度。

The integer division, on the other hand, is computed exactly. 另一方面,整数除法是精确计算的。

Your problem is that, despite the fact that "/" is sometimes called the "true division operator" and its method name is __truediv__ , its behavior on integers is not "true mathematical division". 你的问题是,尽管“/”有时被称为“真正的除法运算符”并且其方法名称是__truediv__ ,但它对整数的行为不是“真正的数学除法”。 Instead it produces a floating point result which inevitably has limited precision. 相反,它产生的浮点结果不可避免地具有有限的精度。

For sufficiently large numbers even the integral part of a number can suffer from floating point rounding errors. 对于足够大的数字,即使数字的整数部分也可能遭受浮点舍入误差。 When 648705536316023400 is converted to a Python float (IEEE double) it gets rounded to 648705536316023424 1 . 当648705536316023400转换为Python float(IEEE double)时,它将四舍五入为648705536316023424 1

I can't seem to find authoritative documentation on the exact behavior of the operators on the built-in types in current Python. 我似乎无法找到关于当前Python中内置类型的运算符的确切行为的权威文档。 The original PEP that introduced the feature states that "/" is equivalent to converting the integers to floating point and then performing floating point division. 引入该特征的原始PEP表明“/”等效于将整数转换为浮点然后执行浮点除法。 However a quick test in Python 3.5 shows that not to be the case. 然而,Python 3.5中的快速测试表明情况并非如此。 If it was then the following code would produce no output. 如果是,那么以下代码将不产生输出。

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

But at least for me it does produce output. 但至少对我来说它确实产生了输出。

Instead it seems to me that Python is performing the division on the numbers as presented and rounding the result to fit in a floating point number. 相反,在我看来,Python正在对所呈现的数字执行除法,并将结果四舍五入以适合浮点数。 Taking an example from that programs output. 以该程序输出为例。

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

The Python standard library does provide a Fraction type and the division operator for a Fraction divided by an int does perform "true mathematical division". Python标准库确实提供了Fraction类型,并且除以int的Fraction的除法运算符执行“真正的数学除法”。

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

However you should be aware of the potentially severe performance and memory implications of using the Fraction type. 但是,您应该了解使用Fraction类型可能带来的严重性能和内存影响。 Remember fractions can increase in storage requirement without increasing in magnitude. 记住,分数可以增加存储需求而不会增加幅度。


To further test my theory of "one rounding vs two" I did a test with the following code. 为了进一步测试我的“四舍五对二”的理论,我用以下代码进行了测试。

#!/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)

And the average error magnitude was substantially smaller for performing the division directly than for converting to float first, supporting the one rounding vs two theory. 并且直接执行除法的平均误差幅度要小于首先转换为浮点数的平均误差幅度,支持一次舍入与两次理论。

1 Note that printing a float directly does not show its exact value, instead it shows the shortest decimal number that will round to that value (allowing lossless round-trip conversion from float to string and back to float). 1请注意,直接打印浮点数不会显示其精确值,而是显示将舍入到该值的最短十进制数(允许从浮点数到字符串并返回浮点数的无损往返转换)。

By "mathematical division", the Python docs mean the exact division on the real numbers. Python 文档中的“数学除法”指的是对实数的精确除法。

Now, back to your question about integer division (aka Euclidean division) vs the floor of a floating-point division (better term than "regular division"), I studied this problem in 2005. What I proved is that for rounding to nearest in radix 2, if x−y is exactly representable, then the floor of the floating-point division x/y, ie math.floor(x/y) , is equal to the integer division.现在,回到你关于整数除法(又名欧氏除法)与浮点除法(比“正则除法”更好的术语)的下限的问题,我在 2005 年研究了这个问题。我证明的是,四舍五入到最接近的基数 2,如果 x−y 可精确表示,则浮点除法 x/y 的下限,即math.floor(x/y) ,等于整数除法。 You can get the paper on my web site or on HAL .您可以在我的网站HAL获取该论文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM