Javascript 浮点错误

Javascript 浮点错误,javascript,floating-point,rounding-error,Javascript,Floating Point,Rounding Error,我一直在努力用javascript解决这个浮点问题。 这是我想做的一个例子: var x1 = 0 for(i=0; i<10; i++) { x1+= 0.2 } var x1=0 对于(i=0;i 0.4->0.600…001)这样做 我曾尝试过parseFloat,toFixed和Math.round在其他线程中提出过建议,但没有一个对我起作用。所以有人能让这项工作起作用,因为我觉得我已经没有选择了。你几乎总是可以忽略浮点“错误”当你进行计算时——除非你真的关心第1

我一直在努力用javascript解决这个浮点问题。 这是我想做的一个例子:

var x1 = 0
for(i=0; i<10; i++)
{
    x1+= 0.2    
}
var x1=0
对于(i=0;i 0.4->0.600…001)这样做


我曾尝试过
parseFloat
toFixed
Math.round
在其他线程中提出过建议,但没有一个对我起作用。所以有人能让这项工作起作用,因为我觉得我已经没有选择了。

你几乎总是可以忽略浮点“错误”当你进行计算时——除非你真的关心第17位有效数字左右,否则它们不会对最终结果产生任何影响

通常,在显示这些值时,您只需要担心舍入问题,对于这些值,
.toFixed(1)
会做得很好

无论发生什么情况,您都无法强制将数字0.6精确转换为该值。最接近的IEEE 754双精度精确为0.5999999999977553950749686919152736663818359375,在JS中的典型精度限制范围内显示为0.5999999999778


事实上,JS甚至不知道0.599999999778!==(例如)0.599999999999300,因为它们的二进制表示形式是相同的。

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

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

1/5可以用一个模式无限重复地写在基数2中

  0.00110011001100110011001100110011001100110011001100110011...
但在浮点运算中,有效位(从最高有效1位开始)必须四舍五入到有限位数(53)

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

  0.0011001100110011001100110011001100110011001100110011010
回到十进制表示法,此舍入误差对应于1/5以上0.00000000000000001110223024625156540236316680908203125的微小超额

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

  0.0011001100110011001100110011001100110011001100110011010
+ 0.0011001100110011001100110011001100110011001100110011010
  ---------------------------------------------------------
  0.0110011001100110011001100110011001100110011001100110100
但当然,2/5以上的超额是0.0000000000000000220446049250313080847263336181640625的两倍

第三个操作0.2+0.2+0.2将生成此二进制数

  0.011001100110011001100110011001100110011001100110011010
+ 0.0011001100110011001100110011001100110011001100110011010
  ---------------------------------------------------------
  0.1001100110011001100110011001100110011001100110011001110
但不幸的是,它需要54位有效位(前导1和尾随1之间的范围),因此需要另一个舍入错误来将结果表示为双精度:

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

因此,3/5以上的超额现在是0.00000000000000008887841970012523233890533447265625

您可以通过使用

x1 = i / 5.0
由于5是用浮点表示的(101.0用二进制表示,3个有效位就足够了),而且i也是这样(最多2^53),所以在执行除法时会有一个舍入误差,IEEE 754保证得到最接近的可能表示

例如,3/5.0表示为:

  0.10011001100110011001100110011001100110011001100110011
回到十进制,默认情况下,该值在3/5下表示为0.0000000000000000220446049250313080847263336181640625


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

您好,欢迎使用。我认为如果您公布您所做的尝试以及它们不令人满意的原因,会有所帮助,因此我们会更好地了解如何帮助您。当您使用浮点时,您必须接受存在舍入错误因为值.6不能用二进制浮点表示,任何代码都不会导致二进制浮点对象具有精确的值。6.您必须承认会有错误。您没有说明这些值会导致什么问题。Ti是的,我可能应该(第一次这么做)埃里克:谢谢你,接受了我不能得到0.6的事实,帮助我改变了我的代码,解决了真正的问题。那就是x1值被用于访问数组值,而a%==0,导致我的if语句无法运行。谢谢你,我对编码和stackoverflow,如果我是一个工具的话,我很抱歉。@EricPostSchil您的编辑不合适。我给出的值是最接近的一个Javascript数字(IEEE 754双精度)。谢谢,我想我是被试图精确地得到0.6所困扰了,接受了这一点,我改变了代码以允许这样做。@Alnitak:不,这个值不是最接近的值。当你显示这个数字时,这个值可能会显示出来,但它不是实际值。这应该是显而易见的,因为它是二进制浮点,并且每个二进制flo点分数以5结尾作为最后一个有效数字。(.5、.25、.125、.0625,…)。我输入的值是IEEE 754规定的实际值。它正好是5404319552844595/9007199254740992。(分母是2**53。)@EricPost可能是IEEE 754尾数的精确十进制表示,对应于0.6,但JS无法提供具有该精度的数字表示,因此附加数字与此无关。请尝试,例如
0.5999999