2012-04-25 7 views
-1

私は単純に小さな部分を二重に追加しようとしているので、Javaの二重変数では非常に奇妙な振る舞いを見てきました。奇妙なJava部分の振る舞い

test = 0.91 

右:

double test = 0; 
test += 0.71; 
test += 0.2; 

今、私は結果があることを期待したいですか?違う!

現実には、これは私が私のテストでは、二重取得数されています。これは非常に近いながら

test = 0.9099999999999999 

は今、それは非常に奇妙な分数の損失だし、長い目で見れば、それは私の中に重大なバグが発生しますプログラム。

フロートで私はさらに奇妙な結果を得ました。

ご協力いただければ幸いです。浮動小数点値のバイナリエンコーディングの魔法だ

おかげ

+0

[二重に小数点を移動する]の複製が可能です。(http://stackoverflow.com/questions/4937402/moving-decimal-places-over-in-a-double) – assylias

答えて

1

(IEEE754探し:http://en.wikipedia.org/wiki/IEEE_754-2008を)。あなたは、物事のこの種を持っていることはありませんようにしてくださいしたい場合は、多分BigDecimalを探しています:

http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html

基本ルール:

  • 浮動を扱うときに平等テストを使用していません小数点数(あなたはギャップをテストする必要があります)
  • あなたは
  • (通常のDecimalFormatを使用して)表示しているラウンド数は、金融アプリケーション
  • のために浮動小数点数を使用していません10
  • フロートは、一般的に限り、あなたはIEEE754
+0

シンプルな私はBigDecimalを使って0.92を受け取りましたか? – Ron

+0

dystroyさんの返信に追加するだけです。内部的に2進数はn、...、128,64,32,16,8,4,2,0,1/2,1/4,1/8、...、1/nで表されます。 – SteJav

+0

Ron、ソリューションはご使用のケースによります。ほとんどの場合、BigDecimalは必要ありません。数値が等しいかどうかを確認するには、単にabs(a-b)<ε(アプリケーションに依存するε)をテストします。それを表示する場合は、(new DecimalFormat( "#。###"))。format(test)を使用します。 –

1

doubleが唯一の最も小数の値を近似することができる理解し、科学や産業活動のために行くための方法です。これは、期待通りの結果を得るために丸めを使用する必要があることを意味します。または、この問題を処理するBigDecimalを使用できます。あなた自身の利益のため

double test = 0; 
test += 0.71; 
test += 0.2; 
System.out.printf("%.2f%n", test); 

プリント

0.91 

System.out.println("0.71 is actually " + new BigDecimal(0.71)); 
System.out.println("0.2 is actually " + new BigDecimal(0.2)); 
System.out.println("0.71+0.2 is actually " + new BigDecimal(0.71 + 0.2)); 
System.out.println("0.91 is actually " + new BigDecimal(0.91)); 
System.out.println("0.71+0.2 == 0.91 is " + (0.71 + 0.2 == 0.91)); 

プリント

0.71 is actually 0.70999999999999996447286321199499070644378662109375 
0.2 is actually 0.200000000000000011102230246251565404236316680908203125 
0.71+0.2 is actually 0.9099999999999999200639422269887290894985198974609375 
0.91 is actually 0.91000000000000003108624468950438313186168670654296875 
0.71+0.2 == 0.91 is false 
+0

数字を印刷するだけでは十分ではありません。私は期待通りにコードが動作するように、「正しい」値を計算しています。 – Ron

4

それについて奇妙なものは全くありません。 0.91,0.71,0.2は、IEEE754浮動小数点値として表現できません。なぜなら、バイナリで表現されていると、小数部分が繰り返されるからです。状況は、基数10の1/3を有限の桁数で表現しようとするのと全く同じです。あなたはそれをすることはできません。

表示されているのは、浮動小数点計算を行う際に通常発生する丸め誤差です。あなたはそれをコードする必要があります。たとえば、信頼性の高い平等を比較することはできません.2つの数値がお互いの小さなデルタ内にあることを確認する必要があります。もう少し深めても理解できる説明はThe Floating Point Guideを参照してください。

+0

それは素晴らしいリンクです - 私はちょっとそのサイトを掘り下げることをお勧めします。多くの人がそこで学び、本当に簡潔に提示されています。 –

0

Javaは小数点を表す浮動小数点というものを使用します。彼らは指数表記を使用します。私の意味は次のとおりです。

倍数(M)と1023〜-1022(E)の指数があります。

数字(N)は、M * 2^Eのように表されます。

4.25は、次のように表されます。

17 * 2^-2。

0.91

は正確にベース2に表現することはできませんが、Javaはかなり近い取得することができます。

0.909999999999 ...

したがって、正確に一緒にこれらの番号を追加することは不可能です。