0

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

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

但是,在这种形式下,我会得到一个舍入错误,0.2 -> 0.4 -> 0.600...001 这样做。

我已经尝试过parseFloattoFixedMath.round在其他线程中提出了建议,但没有一个对我有用。那么有没有人可以完成这项工作,因为我觉得我已经没有选择了。

4

3 回答 3

0

Depending on what you're doing, you may want to do fixed-point arithmetic instead of floating point. For example, if you are doing financial calculations in dollars with amounts that are always multiples of $0.01, you can switch to using cents internally, and then convert to (and from) dollars only when displaying values to the user (or reading input from the user). For more complicated scenarios, you can use a fixed-point arithmetic library.

于 2014-02-12T18:06:33.083 回答
0

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

1/5 可以以 2 为底写成无限重复的模式

  0.00110011001100110011001100110011001100110011001100110011...

但在浮点数中,有效数 - 从最高有效 1 位开始 - 必须四舍五入到有限位数 (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 之间的跨度),因此需要另一个舍入误差来将结果表示为双精度数:

  0.10011001100110011001100110011001100110011001100110100

请注意,数字向上取整,因为默认情况下,即使在完美平局的情况下,浮点数也会四舍五入到最接近的值。我们已经有一个过度的错误,所以运气不好,连续的错误确实累积而不是消灭......

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

您可以通过使用来减少这种错误的累积

x1 = i / 5.0

由于 5 以浮点数精确表示(二进制为 101.0,3 个有效位就足够了),并且由于 i 也是这种情况(最多 2^53),因此在执行除法时存在单个舍入误差,并且 IEEE然后 754 保证您获得最接近的可能表示。

例如 3/5.0 表示为:

  0.10011001100110011001100110011001100110011001100110011

回十进制,数值默认表示为0.000000000000000002220446049250313080847263336181640625下3/5

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

于 2014-02-12T19:15:54.207 回答
0

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

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

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

事实上,JS 甚至无法分辨 0.5999999999999999778 !== (eg) 0.59999999999999999300 因为它们的二进制表示是相同的。

于 2014-02-12T17:29:01.493 回答