【问题标题】:Difference between floor function and floor division楼层功能与楼层划分的区别
【发布时间】:2020-10-23 00:36:43
【问题描述】:

为什么下面的操作答案不一样,而且,既然//本质上是地板除法,那么为什么使用地板功能时输出会不同。

我运行了以下代码:

import math
x = 2**64 -1
print("Original value:", x)
print("Floor division:", x//1)
print("Floor function:", math.floor(x/1))
print("Trunc function:", math.trunc(x/1))
print("Type conversion:", int((x/1)))

输出:

Original value: 18446744073709551615
Floor division: 18446744073709551615
Floor function: 18446744073709551616
Trunc function: 18446744073709551616
Type conversion: 18446744073709551616

既然我所做的只是除以 1,为什么答案不等于原始值?

【问题讨论】:

    标签: python python-3.x


    【解决方案1】:

    float 是 64 位 IEEE-754 二进制浮点值;它只有 53 位的整数精度(除此之外,它还停留在基于将整数值乘以 2 的幂的不精确近似值),并且当您除以 1 时,您在其中放置了一个 64 位值(强制转换为float 在最终调用 round/trunc 之前的结果。基本上,它使float 值尽可能接近您使用的int,不幸的是不等于int(因为这是不可能的),然后对其进行舍入/截断(鉴于该值没有小数部分,只是意味着转换回等效的int 值)。

    // 的楼层划分从来没有问题,因为它纯粹是基于int 的划分(没有任何东西被表示为float),而ints 是(计算机内存的限制)实际上是无限精度。

    【讨论】:

    • 还请注意,由于 python 倾向于舍入到最接近的偶数,因此问题应该只发生在 x 的奇数值上。如果 x 是偶数,则 OP 的操作应该不会出错。
    • @Mercury:将数字中的最后一个 5 四舍五入就是这种情况(当它是“真正的 5”时,实际上不是 49999999993 或其他一些不精确的表示形式)。对于大于float 的最大可表示整数的数字,问题出现在逐渐变大的数字范围中,其中每个范围涵盖2 的某个幂的跨度。在这种情况下,大约有2048 个数字将全部变为18446744073709551616除以1(其中一半高于该数字,另一半低于该数字)。
    • 后续更正:实际上有 3073 个ints 在转换为float 时变为2**64,从2**64 - 1024 开始,一直到2**64 + 2048。通常它是 2 的幂范围,但在这种情况下,我们越过了 2 的幂边界,因此范围比限制高出两倍(float 的表示限制在那时甚至更糟)。
    【解决方案2】:

    / 转换为浮点数。并且浮点算术具有固有的数值错误。一旦您输入x/1,您可能会在x 的原始值上引入错误。一旦出现错误,您基本上无法恢复它。

    这不仅仅是一个整数地板问题:

    x = 2**70 + 123
    print(x-int(x/1))
    
    123
    

    【讨论】:

    • 天啊,你的例子震撼了我。误差差距很大。
    【解决方案3】:

    转换为整数可以揭示浮点数中的不准确性。例如,最接近 21.33 的单精度浮点数略小于 21.33,所以乘以 100 后,结果 Y 略小于 2133.0。

    如果您以典型的浮点格式打印 Y,四舍五入会导致它显示为 2133.00。但是,如果将 Y 分配给整数 I,则不会进行四舍五入,并且该数字会被截断为 2132。

    另外,正如@shadowRanger 所说,// 代表整数除法,因此精确到无限。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-20
      • 2019-04-03
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多