307

合計の順序を変更すると異なる結果が返されるのはなぜですか?

23.53 + 5.88 + 17.64 = 47.05

23.53 + 17.64 + 5.88 = 47.050000000000004

JavaJavaScriptはどちらも同じ結果を返します。

浮動小数点数が 2 進数で表現される方法が原因で、一部の有理数 ( 1/3 - 0.333333... など) を正確に表現できないことを理解しています。

要素の順序を変更するだけで結果に影響するのはなぜですか?

4

6 に答える 6

280

この質問はばかげているかもしれませんが、要素の順序を変更するだけで結果に影響するのはなぜですか?

値の大きさに基づいて、値が丸められるポイントを変更します。例として、 2 進浮動小数点の代わりに、有効桁数 4 桁の 10 進浮動小数点型を使用していたとします。各加算は「無限」の精度で実行され、次に丸められます。最も近い表現可能な数。以下に 2 つの合計を示します。

1/3 + 2/3 + 2/3 = (0.3333 + 0.6667) + 0.6667
                = 1.000 + 0.6667 (no rounding needed!)
                = 1.667 (where 1.6667 is rounded to 1.667)

2/3 + 2/3 + 1/3 = (0.6667 + 0.6667) + 0.3333
                = 1.333 + 0.3333 (where 1.3334 is rounded to 1.333)
                = 1.666 (where 1.6663 is rounded to 1.666)

これが問題になるのに非整数は必要ありません。

10000 + 1 - 10000 = (10000 + 1) - 10000
                  = 10000 - 10000 (where 10001 is rounded to 10000)
                  = 0

10000 - 10000 + 1 = (10000 - 10000) + 1
                  = 0 + 1
                  = 1

これは、小数点以下の桁数が制限されているのではなく、有効桁数が制限されていることが重要であることをより明確に示しています。小数点以下の桁数を常に同じに保つことができれば、少なくとも足し算と引き算では問題ありません (値がオーバーフローしない限り)。問題は、数値が大きくなると、小さい情報が失われることです。この場合、10001 は 10000 に丸められます。(これは、 Eric Lippert が回答で指摘した問題の例です。)

右側の最初の行の値はすべての場合で同じであることに注意することが重要ですdouble。上に示した問題のためだけの問題です。

于 2013-11-06T18:56:32.123 に答える
9

浮動小数点数は IEEE 754 形式を使用して表され、仮数 (仮数) に特定のサイズのビットが提供されます。残念ながら、これにより特定の数の「分数ビルディング ブロック」が得られ、特定の分数値を正確に表すことができません。

あなたのケースで起こっていることは、2番目のケースでは、加算が評価される順序のために、加算がおそらく精度の問題に遭遇しているということです。値を計算していませんが、たとえば、23.53 + 17.64 は正確に表すことができませんが、23.53 + 5.88 は表すことができます。

残念ながら、これは対処しなければならない既知の問題です。

于 2013-11-06T18:57:49.490 に答える
7

それは評価の順序に関係していると思います。数学の世界では和は当然同じですが、バイナリの世界では A + B + C = D ではなく、

A + B = E
E + C = D(1)

したがって、浮動小数点数が得られる二次的なステップがあります。

順番を変えると、

A + C = F
F + B = D(2)
于 2013-11-06T18:53:22.173 に答える