数字 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)
精确平局的一个有趣案例:精确数量在两个可表示的双邻域的距离相同,默认舍入模式是舍入到最近,平局,因此 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/

10-11 20:54