浮点错误消息

时间:2014-02-12 17:24:54

标签: javascript floating-point rounding-error

我一直试图在javascript中解决这个浮点问题。 这是我想要做的一个例子:

var x1 = 0
for(i=0; i<10; i++)
{
    x1+= 0.2    
}

然而,在这种形式下,我将得到一个舍入误差,0.2 - > 0.4 - &gt; 0.600 ... 001这样做。

我在其他帖子中尝试了parseFloattoFixedMath.round,但没有一个对我有效。那么有没有人能够做到这一点,因为我觉得我已经没有选择了。

3 个答案:

答案 0 :(得分:0)

在执行计算时,您几乎总是可以忽略浮点“错误” - 除非您真正关心第17位有效数字,否则它们不会对最终结果产生任何影响。

当您显示这些值时,通常只需要担心舍入,.toFixed(1)可以做得非常好。

无论发生什么,你根本无法将数字0.6强制转换为该值。最接近的IEEE 754双精度正好是0.59999999999999997779553950749686919152736663818359375,它在JS中显示的典型精度限制内显示为0.5999999999999999778

确实JS甚至不能告诉0.5999999999999999778!==(例如)0.5999999999999999300因为它们的二进制表示是相同的。

答案 1 :(得分:0)

根据您正在做的事情,您可能希望使用定点算术而不是浮点算法。例如,如果您使用美元进行财务计算,其金额始终为0.01美元的倍数,您可以在内部切换到使用美分,然后仅在向用户显示值时(或从中读取输入)转换为(和从美元)用户)。对于更复杂的场景,您可以使用定点算术库。

答案 2 :(得分:0)

为了更好地理解舍入误差如何累积,并更深入地了解较低级别的情况,这里有一个小解释:
我将假设底层软件/硬件使用IEEE 754双精度标准,默认舍入模式(舍入到最接近的偶数)。

1/5可以写在基数2中,模式无限重复

  0.00110011001100110011001100110011001100110011001100110011...

但是在浮点数中,有效数 - 从最高有效位开始 - 必须四舍五入到有限位数(53)

因此,当以二进制表示0.2时,存在小的舍入误差:

  0.0011001100110011001100110011001100110011001100110011010

返回十进制表示,此舍入误差对应小于0.000000000000000011102230246251565404236316680908203125以上1/5

第一个操作是精确的,因为0.2 + 0.2就像2 * 0.2,因此不会引入任何额外的错误,就像移动分数点一样:

  0.0011001100110011001100110011001100110011001100110011010
+ 0.0011001100110011001100110011001100110011001100110011010
  ---------------------------------------------------------
  0.0110011001100110011001100110011001100110011001100110100

但当然,超过2/5的比例翻了0.00000000000000002220446049250313080847263336181640625

第三个操作0.2 + 0.2 + 0.2将产生该二进制数

  0.011001100110011001100110011001100110011001100110011010
+ 0.0011001100110011001100110011001100110011001100110011010
  ---------------------------------------------------------
  0.1001100110011001100110011001100110011001100110011001110

但不幸的是,它需要54位有效数字(前导1和尾随1之间的跨度),因此需要另一个舍入误差来将结果表示为double:

  0.10011001100110011001100110011001100110011001100110100

请注意,该数字是舍入的上限,因为默认情况下,即使完美平局,浮点数也会舍入到最近。我们已经有过多的错误,所以运气不好,连续的错误累积而不是消灭......

所以超过3/5的现在是0.000000000000000088817841970012523233890533447265625

使用

可以减少这种误差累积
x1 = i / 5.0

因为5完全用float表示(101.0是二进制的,3个有效位就足够了),并且因为那也是i的情况(最多2 ^ 53),所以执行除法时会出现一个舍入错误,然后IEEE 754保证您获得最接近的可能表示。

例如,3 / 5.0表示为:

  0.10011001100110011001100110011001100110011001100110011

返回小数,该值默认表示为0.00000000000000002220446049250313080847263336181640625(3/5)

请注意,两个误差都非常小,但在第二种情况下为3 / 5.0,幅度比0.2 + 0.2 + 0.2小四倍。