重複の可能性:
浮動小数点数の精度の問題への対処
なぜCでfloatを乗算しようとしたのか(GCC 3.2を使用)、期待どおりに実行されなかったのには非常に驚きました。サンプルとして:
int main() {
float nb = 3.11f;
nb *= 10;
printf("%f\n", nb);
}
ディスプレイ:31.099998
フロートの実装方法と、なぜこの予期しない動作が発生するのかについて興味があります。
重複の可能性:
浮動小数点数の精度の問題への対処
なぜCでfloatを乗算しようとしたのか(GCC 3.2を使用)、期待どおりに実行されなかったのには非常に驚きました。サンプルとして:
int main() {
float nb = 3.11f;
nb *= 10;
printf("%f\n", nb);
}
ディスプレイ:31.099998
フロートの実装方法と、なぜこの予期しない動作が発生するのかについて興味があります。
まず、フロートを掛けることができます。あなたが抱えている問題は、掛け算そのものではなく、あなたが使った元の数です。乗算はある程度の精度を失う可能性がありますが、ここでは、乗算した元の数値は精度を失った状態から始まりました。
これは実際には予想される動作です。float
はバイナリ表現を使用して実装されているため、10進値を正確に表すことはできません。
詳細については、 MSDNを参照してください。
また、floatの説明で、有効数字6〜7桁の精度があることがわかります。あなたの例では、31.099998
有効数字を7桁に丸めると31.1
、ここで期待どおりに機能するようになります。
double
タイプはもちろんより正確ですが、書き込んだ数値が10進数であるのに対し、2進数表現であるため、丸め誤差があります。
10進数の完全な精度が必要な場合は、10進数タイプを使用する必要があります。このタイプは、C#などの言語で存在します。http://msdn.microsoft.com/en-us/library/system.decimal.aspx
有理数表現を使用することもできます。数値を2つの整数の除算として表すことができる限り、完全な精度が得られる2つの整数を使用します。
これは期待どおりに機能しています。コンピューターは整数から浮動小数点値を計算しようとしているため、有限の精度を持っています。これにより、浮動小数点が不正確になります。
浮動小数点ウィキペディアのページでは、表現とその結果生じる精度の問題について、ここで説明できるよりもはるかに詳細に説明しています:)
興味深い現実世界のサイドノート:これが、整数(セント)を使用して多くのお金の計算が行われる理由の一部です-精度の欠如でコンピューターにお金を失わせないでください!$ 0.00001が欲しい!
3.11という数字は2進数で表すことはできません。24の有効ビットで取得できる最も近いものは11.0001110000101000111101で、10進数で3.1099998950958251953125になります。
数値3.11が金額を表すことになっている場合は、10進数表現を使用する必要があります。
Pythonコミュニティでは、これに驚かされることがよくあります。そのため、この問題については、十分にテストおよびデバッグされたFAQとチュートリアルセクションがあります(もちろん、CではなくPythonで表現されていますが、Pythonは浮動小数点演算を委任しているためです。とにかく、基盤となるCとハードウェアには、floatのメカニズムのすべての説明が引き続き適用されます)。
もちろん、これは乗算のせいではありません。乗算するステートメントを削除すると、nb
とにかく同様の問題が発生します。
ウィキペディアの記事から:
浮動小数点数がすべての実数を正確に表すことができないという事実、および浮動小数点演算が真の算術演算を正確に表すことができないという事実は、多くの驚くべき状況につながります。これは、コンピューターが一般的に数値を表す有限の精度に関連しています。
浮動小数点は、基数10ではなく基数2(2進数であるため0または1)を使用するため、正確ではありません。また、多くの人が前に述べたように、基数2を基数10に変換すると、丸めの精度の問題が発生します。