【问题标题】:Python float to integer errorPython浮点到整数错误
【发布时间】:2018-06-16 03:31:00
【问题描述】:

我很难理解这一点:

>>> 52920*(15303855351918+15303855298999)/2.0 == 809880023823263820
False
>>> 52920*(15303855351918+15303855298999)/2.0 == 809880023823263820.0
True
>>> (52920*(15303855351918+15303855298999)/2.0) - 809880023823263820
0.0
>>> int(52920*(15303855351918+15303855298999)/2.0)
809880023823263872
>>> int(52920/2.0)*(15303855351918+15303855298999)
809880023823263820

运行 Python 3.5.3

数字 809880023823263820 显然可以表示为整数,因为它是 a.p. 的总和。具有所有整数参数的系列。第 1 次和第 4 次计算的解释是什么?

【问题讨论】:

  • 浮点数是这种“精确”数字的错误抽象。精度位数太多。

标签: python floating-point type-conversion int


【解决方案1】:

Python int 对象具有无限精度(仅受内存限制)。 float 对象没有无限精度;数字表示为一个指数和一个显着性,后者由 53 个二进制分数组成。二进制分数不能代表所有可能的十进制数,这就是这里发生的情况。

809880023823263820 不能用二进制分数清楚地表示:

>>> float(809880023823263820)
8.098800238232639e+17
>>> format(float(809880023823263820), 'f')
'809880023823263872.000000'

号码存储为注意最后两位;他们是72,而不是20

请注意,浮点值始终存储为分数,指数确定小数点的位置;没有“整数部分”。非常大和非常小的数字都简单地表示为小数点按指数移动的分数。

对于第三个表达式,Python 将数字转换为通用类型。从浮点数中减去整数会首先将整数转换为浮点数。由于float(809880023823263820)- 运算符左侧的结果相同的浮点值,因此结果为0.0

来自表达式参考文档的Binary arithmetic operations section

-(减法)运算符产生其参数的差异。数字参数首先转换为通用类型。

还有一个单独的Arithmetic conversions section 记录了这种转换是如何完成的:

当下面对算术运算符的描述使用短语“数字参数转换为通用类型”时,这意味着内置类型的运算符实现如下:

  • 如果任一参数是复数,则将另一个转换为复数;
  • 否则,如果任一参数为浮点数,则将另一个转换为浮点数;
  • 否则,两者都必须是整数且无需转换。

您可能想要探索有理数的不同表示,fractionsdecimal 模块。或者让您将有理数作为抽象分数处理,或者让您配置数值精度。

【讨论】:

  • 好的,我知道有效数字没有足够的精度来表示确切的数字。但是第三次​​计算如何产生正确的结果呢?
  • @DebD:添加了解释。 float - int 将整数强制为浮点数。
【解决方案2】:

浮点数的精度有限,而整数则具有任意精度。这意味着您不能在 Python 中将每个整数都表示为浮点数!如果你检查一下,你可以很容易地看到这一点:

>>> 809880023823263820 == 809880023823263820.0
False
>>> 809880023823263820 == int(809880023823263820.0)
False

来自Wikipedia

53 位有效数字精度提供 15 到 17 位有效十进制数字精度 (2−53 ≈ 1.11 × 10−16)。如果将最多 15 位有效数字的十进制字符串转换为 IEEE 754 双精度表示,然后再转换回具有相同位数的十进制字符串,则最终结果应与原始字符串匹配。

但是你的整数有 18 位,所以你不应该期望一个浮点数可以准确地表示那个整数。有些值可以精确表示,长度超过 18 位,但条件必须是“正确的”(例如 2 的幂):

>>> 2.0 ** 80 + 1 == 2 ** 80 + 1
False
>>> 2.0 ** 80 == 2 ** 80
True

您的最后一个示例实际上有点误导,因为52920/2.0 可以完全表示为浮点数,并且因为您实际上将其转换为整数,所以计算将完全使用整数完成并产生准确的整数结果。

在一般情况下,您可以使用Fraction 来准确表示该值:

>>> from fractions import Fraction
>>> Fraction(52920*(15303855351918+15303855298999), 2) == 809880023823263820
True

请注意这里的, 2 而不是/ 2.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-15
    • 2020-07-26
    • 2015-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 2018-06-07
    相关资源
    最近更新 更多