为什么python中不同浮点数的差值可以是0?[复制]

Why can the difference of different floating numbers be 0 in python? [duplicate]

提问人:olli 提问时间:1/26/2023 最后编辑:ShadowRangerolli 更新时间:1/29/2023 访问量:193

问:

这个问题在这里已经有答案了:
Python 中大整数/数字的浮点数到整数到整数的 int 类型转换 (2 个答案)
10个月前关闭。

为什么 python3 中以下代码的结果为 0?

a = "4.15129406851375e+17"
a = float(a)
b = "415129406851375001"
b = float(b)
a-b
python-3.x 浮点 精度 largenumber

评论

0赞 Scott Hunter 1/26/2023
浮点错误。
1赞 ShadowRanger 1/26/2023
@khelwood:这不是一个很好的复制品;它涵盖了“浮点数学实际上是破损的(对于破损的某个定义)”,但这里的问题是超出了表示整数的限制,而不是小数点右边精度的问题(即使这两个问题在某种程度上相关)。float
1赞 Gábor Fekete 1/26/2023
使用内置包将字符串转换为 S,然后它会打印正确的值decimaldecimal.Decimal-1
1赞 9769953 1/26/2023
投票重新开放:感觉像是另一种情况,即接近投票与一般问题相关联(OP 甚至可能意识到),但更精确的答案在这里更合适。
1赞 ShadowRanger 1/26/2023
谢谢@kaya!浮点数学坏了吗?始终是一个有用的参考,只是不是重复的(答案切向触及相关信息,没有细节),但我找不到特定于 s 对大数字失去精度的复制品。float

答:

1赞 ShadowRanger 1/26/2023 #1

发生这种情况是因为 和 都大于 C 的整数表示限制(这是 Python 的实现方式)。4151294068513750014.15129406851375e+17doublefloat

通常,C 是 IEEE 754 64 位二进制浮点值,这意味着它们具有 53 位整数精度(最后一个连续的整数值可以表示,后跟 ;它不能表示)。问题是,需要 59 位整数精度来存储(将提供此信息)。当一个值对于单独使用有效数(整数分量)来说太大时,浮点值的指数分量用于将较小的整数值缩放为 2 的幂,使其大致在原始值的大致范围内,但这意味着可表示的整数开始跳跃,首先是 2(因为您需要 >53 位), 然后是 4(对于 >54 位),然后是 8(>55 位),然后是 16(>56 位),依此类推,对于无法用 53 位表示的每个幅度位,在可表示值之间跳过两倍的距离。doublefloat2 ** 53 - 12 ** 532 ** 53 + 1415129406851375001(415129406851375001).bit_length()

在您的例子中,两个数字的整数值都转换为 ,其整数值为 (将显示真正的整数值;它们太大而无法包含任何小数分量),在低数字中失去了精度。float415129406851374976print(int(a), int(b))

如果您需要任意精确的以 10 为基数的浮点数学运算,请将 替换为 decimal。十进制(方便的是,您的值已经是字符串,因此您不会冒着在键入 a 的方式和存储的实际值之间失去精度的风险);默认精度将处理这些值,如果需要更大的值,可以增加它。如果这样做,则会获得预期的行为:floatfloat

from decimal import Decimal as Dec  # Import class with shorter name

a = "4.15129406851375e+17"
a = Dec(a)  # Convert to Decimal instead of float
b = "415129406851375001"
b = Dec(b)  # Ditto
print(a-b)

输出 .如果你在交互式解释器中回显它而不是使用 ,你会看到 ,这是 s 的形式,但它是数字的,如果转换为 ,或者通过任何不使用 的方法字符串化,例如 ,它显示为 。-1printDecimal('-1')reprDecimal-1intreprprint-1

在线试用!