数字 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/