我一直试图在javascript中解决这个浮点问题。 这是我想要做的一个例子:
var x1 = 0
for(i=0; i<10; i++)
{
x1+= 0.2
}
然而,在这种形式下,我将得到一个舍入误差,0.2 - > 0.4 - &gt; 0.600 ... 001这样做。
我在其他帖子中尝试了parseFloat
,toFixed
和Math.round
,但没有一个对我有效。那么有没有人能够做到这一点,因为我觉得我已经没有选择了。
答案 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小四倍。