【问题标题】:Is integer division always equal to the floor of regular division?整数除法总是等于正除法的下限吗?
【发布时间】:2019-05-22 07:49:54
【问题描述】:

对于大商,整数除法 (//) 似乎不一定等于正除法的下限 (math.floor(a/b))。

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

整数的下除法得到一个整数;结果是数学除法的结果,“地板”函数应用于结果。

然而,

math.floor(648705536316023400 / 7) = 92672219473717632

648705536316023400 // 7 = 92672219473717628

'{0:.10f}'.format(648705536316023400 / 7) 产生“92672219473717632.0000000000”,但小数部分的最后两位应该是 28 而不是 32。

【问题讨论】:

  • 如果从下面的答案中不清楚 - 问题是当文档用“数学除法”定义“地板除法”(//)时,术语“数学除法” not 是否引用 Python“部门”/。相反,“除法”/ 和“地板除法”// 是真(“数学”)除法的两个不同近似值。

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


【解决方案1】:

Python 文档中的“数学除法”是指实数的精确除法。

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

【讨论】:

    【解决方案2】:

    您的问题是,尽管“/”有时被称为“真正的除法运算符”并且它的方法名称是__truediv__,但它对整数的行为并不是“真正的数学除法”。相反,它会产生一个不可避免地具有有限精度的浮点结果。

    对于足够大的数字,即使数字的整数部分也会出现浮点舍入错误。当 648705536316023400 转换为 Python 浮点数(IEEE 双精度)时,它会四舍五入为 6487055363160234241

    我似乎无法找到有关当前 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 标准库确实提供了 Fraction 类型,并且 Fraction 除以 int 的除法运算符执行“真正的数学除法”。

    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】:

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

      然而,对于整数除法,Python 使用其无限的整数范围,因此结果是正确的。

      另见"Semantics of True Division" in PEP 238

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

      【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-13
        • 1970-01-01
        • 2012-03-16
        • 2015-09-29
        • 1970-01-01
        • 1970-01-01
        • 2016-03-16
        • 1970-01-01
        相关资源
        最近更新 更多