my answer to another question (reasonably) duped 的修改版本到这个:
发生这种情况是因为 46700000000987654321 大于 C double 的整数表示限制(这是 Python float 的实现方式)。
通常,Cdoubles是IEEE 75464位二进制浮点值,其中means they have 53 bits of integer precision(最后一个连续的整数值float可以表示是2 ** 53 - 1后跟2 ** 53;它不能表示@987654333 @).问题是,46700000000987654321 需要 66 位整数精度来存储((46700000000987654321).bit_length() 将提供此信息)。当一个值对于尾数(整数部分)单独来说太大时,浮点值的指数部分用于按 2 的幂缩放较小的整数值大致在原始值的范围内,但这意味着可表示的整数开始跳过,首先是 2(因为你需要 >53 位),然后是 4(对于 >54 位),然后是 8(>55 位),然后16(> 56 位)等,对于超过 53 位的每个额外位,在可表示值之间跳过两倍。
在您的情况下,转换为float 的46700000000987654321 的整数值为46700000000987652096(如您所述),低位数字的精度丢失。
如果您需要任意精确的 base-10 浮点数学,请替换您对 float with decimal.Decimal 的使用(方便的是,您的初始值已经是一个字符串,因此您不会在输入 float 之间失去精度的风险和存储的实际值);默认精度将处理这些值,如果您需要更大的值,您可以增加它。如果你这样做(并将 a 转换为 int 进行比较,因为 str 永远不等于任何数字类型),你会得到你期望的行为:
from decimal import Decimal as Dec, getcontext
a = "46700000000987654321"
b = Dec(a); print(b) # => 46700000000987654321
c = int(b); print(c) # => 46700000000987654321
print(int(a) == c) # => True
Try it online!
如果您在交互式解释器中回显 Decimals 而不是使用 print,您会看到 Decimal('46700000000987654321'),它是 Decimals 的 repr 形式,但它在数字上是 46700000000987654321,如果转换为 int,或通过任何不使用 repr 的方法进行字符串化,例如print,它显示为46700000000987654321。