たとえば、ドルでは、0.01ドル未満の精度はありません。
まあ、本当に?
IEEE 754浮動小数点数として通貨を保存しない理由の古い問題。
IEEE 754 浮動小数点数にインチを自由に格納してください。彼らはあなたが期待する方法を正確に保存します。
ルーラーを1インチの小数に分割する目盛りを使用して保存できるIEEE 754浮動小数点数の金額を自由に保存してください。
どうして?なぜなら、IEEE 754を使用するとき、それが保存方法だからです。
インチについてのことは、それらが半分に分割されていることです。ほとんどの種類の通貨に関することは、通貨が10分の1に分割されていることです(一部の通貨はそうではありませんが、集中し続けましょう)。
ほとんどのプログラミング言語では、IEEE 754浮動小数点数への入出力は10進数で表現されることを除いて、この違いはそれほど複雑ではありません。それらは小数で保存されないため、これは非常に奇妙です。
このため、コンピュータに保存するように要求したときに、ビットがどのように奇妙なことをするかを見ることができません0.1
。あなたはそれに対して数学をするときだけ奇妙さを見る、そしてそれは奇妙なエラーを持っている。
以下からのジョシュブロッホの効果的なJavaの:
System.out.println(1.03 - .42);
生産する 0.6100000000000001
これについて最も言っているのは1
、右側に座っている方法ではありません。それを得るために使用しなければならなかったのは奇妙な数字です。最も一般的な例0.1
を使用するのではなく、問題を示し、それを隠す丸めを回避する例を使用する必要があります。
たとえば、なぜこれが機能するのですか?
System.out.println(.01 - .02);
生産する -0.01
幸運になったからです。
私は時々「幸運」になるので、診断が難しい問題は嫌いです。
IEEE 754では、0.1を正確に格納することはできません。しかし、0.1を保存するように要求してから印刷するように要求すると、0.1が表示され、すべてが正常であると思われます。大丈夫ではありませんが、0.1に戻すのに丸めているため、それを見ることができません。
一部の人々は、これらの不一致を丸め誤差と呼ぶことにより、他の人々と一体を混同しています。いいえ、これらは丸め誤差ではありません。丸めは、本来の目的を果たし、小数ではないものを小数に変換して、画面に印刷できるようにすることです。
ただし、これにより、数値の表示方法と保存方法の不一致が隠されます。丸めが発生してもエラーは発生しませんでした。正確に保存できないシステムに数値を入力することを決定し、保存されていないときに正確に保存されていると仮定したときに発生しました。
πが計算機に正確に保存されることを期待する人はいません。そのため、問題は精度についてでさえありません。予想される精度についてです。コンピューター0.1
は、電卓と同じように10分の1を表示するため、電卓と同じように完全に1/10を保存することが期待されます。彼らはしません。コンピュータは高価なので、これは驚くべきことです。
不一致を示しましょう:
1/2と0.5が完全に揃っていることに注意してください。しかし、0.1はちょうど揃っていません。2で除算し続ければ、確実に近づくことができますが、決して正確にヒットすることはありません。そして、2で除算するたびにますます多くのビットが必要になります。したがって、2で除算するシステムで0.1を表すには、無限のビット数が必要です。私のハードディスクはそれほど大きくありません。
したがって、IEEE 754はビットが足りなくなると試行を停止します。家族の写真を撮るためにハードドライブにスペースが必要なので、これは素晴らしいことです。いやいや。家族の写真。:P
とにかく、入力するものと表示されるものは小数(右側)ですが、格納するのは2 進数(左側)です。時々、それらはまったく同じです。時々そうではありません。単にそうではないのに同じであるように見えることもあります。それが丸めです。
特に、ある通貨で値を保存して印刷できるようにするには、何を知る必要がありますか?
あなたが私の小数ベースのお金を処理している場合は、フロートまたはダブルを使用しないでください。
10分の1ペニーのようなものが関与しないと確信している場合は、ペニーを保管するだけです。そうでない場合は、この通貨の最小単位が何であるかを把握し、それを使用します。できない場合は、BigDecimalのようなものを使用します。
私の純資産はおそらく64ビット整数に常にうまく収まりますが、BigIntegerのようなものはそれより大きいプロジェクトでうまく機能します。ネイティブ型よりも遅いだけです。
保存方法を理解することは、問題の半分にすぎません。また、それを表示できる必要があります。優れた設計は、これら2つのことを分離します。ここでフロートを使用する際の本当の問題は、これらの2つのことが一緒になってしまうことです。