javascript - 对浮点相等性测试感到困惑?

标签 javascript floating-point precision

无法准确表示数字 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/

相关文章:

c - 将变量传递到另一个文件

c# - .NET 日期时间从字符串转换为日期时间时的毫秒精度问题

javascript htmlencode 在 FireFox XUL 中不起作用?

javascript - Angular 观察对象不在范围内

javascript - 只需运行一次 location.reload 方法

javascript - 在输入上使用 Change,然后修改输入的 ATTR?

c# - 为什么当我将 double 与零进行比较时 Resharper 会提示?

java - 1.0E7 的浮点当量

c++ - C++中long double的精度是多少?

c++ - C/C++ 中 pow() 函数的实现是否因平台或编译器而异?