0

この浮動小数点の問題を JavaScript で解決しようとしています。これは私がやりたいことの例です:

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

ただし、この形式では、0.2 -> 0.4 -> 0.600...001 という丸めエラーが発生します。

を試しparseFloat、他のスレッドtoFixedMath.round提案しましたが、どれもうまくいきませんでした。選択肢がなくなったと感じているので、これを機能させることができる人はいますか。

4

3 に答える 3

0

計算を実行している間は、ほとんどの場合、浮動小数点の「エラー」を無視できます。17 番目の有効桁数を本当に気にしない限り、最終結果に違いはありません。

通常は、これらの値を表示するときに丸めを気にするだけで.toFixed(1)十分です。

Whatever happens you simply cannot coerce the number 0.6 into exactly that value. The closest IEEE 754 double precision is exactly 0.59999999999999997779553950749686919152736663818359375, which when displayed within typical precision limits in JS is displayed as 0.5999999999999999778

Indeed JS can't even tell that 0.5999999999999999778 !== (e.g) 0.5999999999999999300 since their binary representation is the same.

于 2014-02-12T17:29:01.493 に答える
0

丸め誤差がどのように蓄積されているかをよりよく理解し、より低いレベルで何が起こっているかについてより多くの洞察を得るために、ここに簡単な説明があります:
IEEE 754 倍精度標準が基礎となるソフトウェア/ハードウェアによってデフォルトの丸めモードで使用されていると仮定します (最も近い偶数に丸める)。

1/5 は底 2 で無限に繰り返されるパターンで書くことができます

  0.00110011001100110011001100110011001100110011001100110011...

しかし、浮動小数点では、最上位 1 ビットから始まる仮数を有限のビット数 (53) に丸める必要があります。

そのため、0.2 を 2 進数で表すと、小さな丸め誤差があります。

  0.0011001100110011001100110011001100110011001100110011010

10 進数表現に戻ると、この丸め誤差は 1/5 をわずかに超える 0.00000000000000011102230246251565404236316680908203125 に相当します。

0.2+0.2 は 2*0.2 に似ているため、最初の操作は正確であり、追加のエラーは発生しません。これは分数ポイントをシフトするようなものです。

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

しかしもちろん、2/5 を超える超過分は 2 倍になります。

3 番目の演算 0.2+0.2+0.2 は、この 2 進数になります。

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

しかし残念なことに、54 ビットの有意桁 (先頭の 1 と末尾の 1 の間のスパン) が必要なため、結果を double として表すには別の丸め誤差が必要です。

  0.10011001100110011001100110011001100110011001100110100

デフォルトでは、浮動小数点数は完全に引き分けの場合でも最も近い値に丸められるため、数値が上に丸められていることに注意してください。すでに過剰なエラーが発生していたので、運が悪かったため、エラーが連続して消滅するのではなく蓄積されました...

したがって、3/5 を超える超過分は 0.000000000000000088817841970012523233890533447265625 になります。

を使用して、このエラーの蓄積を少し減らすことができます

x1 = i / 5.0

5 は float で正確に表され (2 進数では 101.0、有効桁数 3 ビットで十分)、i の場合も同様 (2^53 まで) であるため、除算の実行時に 1 つの丸め誤差が発生し、IEEE 754 は、可能な限り最も近い表現を取得することを保証します。

たとえば、3/5.0 は次のように表されます。

  0.10011001100110011001100110011001100110011001100110011

10 進数に戻すと、値はデフォルトで表されます。

どちらのエラーも非常に小さいことに注意してください。ただし、2 番目のケースでは 3/5.0 であり、0.2+0.2+0.2 の 4 分の 1 です。

于 2014-02-12T19:15:54.207 に答える