double r = 11.631;
double theta = 21.4;
デバッガーでは、これらは および として表示され11.631000000000000
ます21.399999618530273
。
どうすればこれを回避できますか?
double r = 11.631;
double theta = 21.4;
デバッガーでは、これらは および として表示され11.631000000000000
ます21.399999618530273
。
どうすればこれを回避できますか?
これらの精度の問題は、浮動小数点数の内部表現が原因であり、回避するためにできることはあまりありません。
ところで、これらの値を実行時に出力すると、少なくとも最新の C++ コンパイラを使用して、正しい結果が得られることがよくあります。ほとんどの操作では、これは大きな問題ではありません。
私は、Excel2007での同様のバイナリ浮動小数点精度の問題を扱っているJoelの説明が好きでした。
最後に011001100110がたくさんあるのを見てください。これは、0.1が2進数で正確に表現されていないためです...これは、2進数の繰り返しです。これは、1/3が10進数で表現されていないようなものです。1/3は0.33333333であり、3を永遠に書き続ける必要があります。忍耐力を失うと、何かが不正確になります。
したがって、10進数で、3 * 1/3を実行しようとして、3を永遠に書く時間がなかった場合、結果は1ではなく0.99999999になり、人々は怒ります。あなたが間違っているため。
次のような値がある場合:
double theta = 21.4;
そして、あなたがしたい:
if (theta == 21.4)
{
}
theta の値が実際に 21.4 に近いかどうかを確認する必要がありますが、必ずしもその値である必要はありません。
if (fabs(theta - 21.4) <= 1e-6)
{
}
これは一部プラットフォーム固有のものであり、どのプラットフォームを使用しているかはわかりません。
また、実際に見たいものを知っている場合もあります。デバッガーは、変数に格納されている正確な値を表示しています。.NETの2 進浮動小数点数に関する私の記事では、double に格納された絶対に正確な数値を表示できるC# クラスがあります。現在、オンライン バージョンは機能していません。別のサイトにアップしようと思います。
デバッガーが「実際の」値を認識した場合、何を表示するかについて判断を下す必要があります。小数点以下の桁数に丸められた値、またはより正確な値が表示される可能性があります。一部のデバッガーは、他のデバッガーよりも開発者の心を読み取るのに優れていますが、これは 2 進浮動小数点数の根本的な問題です。
decimal
精度の限界で安定性が必要な場合は、固定小数点型を使用します。オーバーヘッドがあり、浮動小数点に変換する場合は明示的にキャストする必要があります。浮動小数点に変換すると、気になる不安定性が再び発生します。
または、それを乗り越えて、浮動小数点演算の限られた精度で作業することを学ぶことができます。たとえば、丸めを使用して値を収束させたり、イプシロン比較を使用して許容範囲を記述したりできます。「Epsilon」は、許容範囲を定義するために設定する定数です。たとえば、2 つの値が互いに 0.0001 以内にある場合、それらを等しいと見なすことができます。
演算子のオーバーロードを使用して、イプシロンの比較を透過的にすることができると思います。それはとてもクールだろう。
仮数指数表現の場合、EPSILON は表現可能な精度内に収まるように計算する必要があります。数値 N の場合、イプシロン = N / 10E+14
System.Double.Epsilon
型の表現可能な最小の正の値ですDouble
。私たちの目的には小さすぎます。同等性テストに関する Microsoft のアドバイスを読む
私は以前にこれに出くわしました (私のブログで) - 「無理数」が異なることに驚かされる傾向があると思います。
ここで「不合理」とは、この形式では正確に表現できないという事実を指しているだけです。実数の無理数 (π - pi など) はまったく正確に表すことができません。
ほとんどの人は、1/3 が 10 進数で機能しないことに精通しています: 0.3333333333333...
奇妙なことに、1.1 は float では機能しません。人々は、10 進数値が浮動小数点数で機能することを期待しています。
1.1 は 11 x 10^-1 です
実際に彼らがベース2にいるとき
1.1 は 154811237190861 x 2^-47 です
これを避けることはできません。1/3 と同じように、いくつかの float が「不合理」であるという事実に慣れる必要があります。
21.399999618530273 は21.4 の単精度(float) 表現だと思います。デバッガーがどこかで double から float にキャストしているようです。
これを回避する 1 つの方法は、 BCDなど、10 進数を表す別の方法を使用するライブラリを使用することです。
Javaを使用していて精度が必要な場合は、浮動小数点の計算にBigDecimalクラスを使用してください。遅いですが安全です。
固定バイト数の浮動小数点数を使用しているため、これを避けることはできません。実数とその限定された表記との間に可能な同型はありません。
しかし、ほとんどの場合、単に無視することができます。21.4==21.4 は、同じエラーで同じ数値であるため、依然として true です。ただし、float と double の誤差が異なるため、21.4f==21.4 は正しくない可能性があります。
固定精度が必要な場合は、おそらく固定小数点数を試す必要があります。または整数でさえ。たとえば、デバッグ ページャーに渡すために int(1000*x) をよく使用します。
気になる場合は、デバッグ中に一部の値を表示する方法をカスタマイズできます。注意して使用してください:-)
javadocによると
「数値演算子のオペランドの少なくとも 1 つが double 型である場合、
演算は 64 ビット浮動小数点演算を使用して実行され、
数値演算子の結果は double 型の値になります。他のオペランドがが double でない場合、
数値昇格 (§5.6) によって double 型に拡張されます (§5.1.5)。"