无法准确表示数字 6.35:
alert( 6.35.toFixed(20) ); // 6.34999999999999964473
但为什么 6.35 * 10 == 63.5
是真的?
6.35不准,10准,63.5准。我不明白(不准确 * 准确)如何等于准确。
最佳答案
这是一个逻辑错误:最后的操作 6.35 * 10.0 是不准确的而不是准确的。
只是可能会出现连续的几个“舍入误差”消失的情况,也可能会出现它们累积的情况。
最接近 635/100 的 double 是 635/100 - 1/2,814,749,767,106,560
或者,如果您愿意:635/100 - 1/(10 * 2^48)
因此,准确的 *10
操作应该回答 635/10 - 1/(2^48)
。
但是这个数量不能表示为 double (见下文)...
所以最后的操作是不准确的。
这两个邻居是 63.5(正好是 635/10
)及其前身 635/10 - 1/(2^47)
。
exact tie 的一个有趣的例子:精确的数量是两个可表示的双邻居的相同距离,默认的舍入模式是舍入到最近,tie to even,所以 FPU 会选择偶数尾数的 double,即 635/10
。
这是运气还是 IEEE 754 算法的一个很好的属性?
如果我在 Squeak/Pharo Smalltalk 中评估这个片段(它有精确的分数和精确算术值的比较):
(1 to: 10000) count: [:x | (x/10.0) = (x/10) and: [(x/100.0) ~= (x/100)]].
我遇到了 1600 种情况,其中 x/10 可以精确表示为 double ,而 x/100 不是。
如果我选择这 1600 个案例,并验证舍入误差是否消失:
((1 to: 10000) select: [:x | (x/10.0) = (x/10) and: [(x/100.0) ~= (x/100)]])
count: [:x | (x/100.0*10) = (x/10)]
我计算了 1600 个错误消除的案例中的 1600 个,因此这是 IEEE754 算法的一个很好的属性。但这仍然是运气。
如果我通过除以 1000.0 再乘以 100 来重试,我会得到这个问题的错误答案:
((1 to: 10000) select: [:x | (x/10.0) = (x/10) and: [(x/1000.0) ~= (x/1000)]])
allSatisfy: [:x | (x/1000.0*100) = (x/10)]
在 1920 年中,有 1649 个案例的答案是正确的,这已经是一个不错的分数。
关于javascript - 对浮点相等性测试感到困惑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58908105/