浮動小数点演算は壊れていますか?
概要
次のコードを考えてみましょう。
0.1 + 0.2 == 0.3 -> false
0.1 + 0.2 -> 0.30000000000000004
なぜこのような不正確さが起こるのでしょうか?
解決策
2 進浮動小数点演算は次のように機能します。ほとんどのプログラミング言語では、IEEE 754 標準に基づいています。問題の核心は、この形式では数値が 2 の累乗の整数として表現されることです。分母が 2 のべき乗ではない有理数 (1/10 である 0.1 など) は正確に表現できません。
標準の binary64 形式の 0.1 の場合、表現は次のように正確に書くことができます。
対照的に、1/10 である有理数 0.1 は、次のように正確に書くことができます。
プログラム内の定数 0.2 と 0.3 も、実際の値の近似値になります。 0.2 に最も近い double は有理数 0.2 より大きいですが、0.3 に最も近い double は有理数 0.3 より小さいことが起こります。 0.1 と 0.2 の合計は有理数 0.3 より大きくなり、コード内の定数と一致しません。
浮動小数点演算の問題をかなり包括的に扱うには、「すべてのコンピュータ科学者が浮動小数点演算について知っておくべきこと」を参照してください。わかりやすい説明については、floating-point-gui.de を参照してください。
単純な古い 10 進数 (基数 10) にも同じ問題があり、1/3 のような数値が 0.333333333 になるのはそのためです…
あなたは、10 進法では簡単に表現できるものの、2 進法には適合しない数値 (3/10) に遭遇しました。これは (ある程度は) 両方の方向にも当てはまります。1/16 は 10 進数では醜い数 (0.0625) ですが、2 進数では 10,000 分の 1 を 10 進数で表す (0.0001)** と同じくらいきれいに見えます。私たちの日常生活で 2 を基数とする数値体系を使用する習慣があれば、その数値を見ても、何かを半分にし、さらに半分にし、それを何度も繰り返すことでそこに到達できることが直感的に理解できるでしょう。
もちろん、これは浮動小数点数がメモリに格納される方法とまったく同じではありません (浮動小数点数は科学表記法の形式を使用します)。ただし、これは、私たちが通常扱いたい「現実世界」の数値は 10 の累乗であることが多いため、2 進浮動小数点の精度エラーが発生する傾向があることを示しています。これは、単に 10 進数システムを使用しているためです。今日。これが、「7 つ中 5 つ」ではなく 71% などと言う理由でもあります (5/7 は 10 進数で正確に表すことができないため、71% は近似値です)。
つまり、いいえ: 2 進浮動小数点数は壊れているわけではなく、他の N 進数の数値体系と同じようにたまたま不完全であるだけです :)
実際には、この精度の問題は、浮動小数点数を表示する前に、丸め関数を使用して、浮動小数点数を目的の小数点以下の桁数に四捨五入する必要があることを意味します。
また、同等性テストを、ある程度の許容範囲を許容する比較に置き換える必要があります。これは、次のことを意味します。
if (x == y) { … } の場合は実行しないでください。
代わりに、 if (abs(x - y) < myToleranceValue) { … } を実行します。
選択した言語では「イプシロン」スタイルの定数に注意してください。これらは許容値として使用できますが、大きな数値を使用した計算ではイプシロンのしきい値を超える可能性があるため、その有効性は扱う数値の大きさ (サイズ) によって異なります。ここで、abs は絶対値です。 myToleranceValue は、特定のアプリケーションに合わせて選択する必要があります。これは、どれだけの「余裕」を許容するか、および比較する最大値が何になるか (精度が失われるため) に大きく関係します。問題)。