2011-12-28 14 views
3

基本的に、私は435の整数に変換される4.35 * 100 = 435.0のときに、以下のコードが434を出力する理由を理解できません。Java丸めオフ問題

これについての簡単な説明は何ですか?これは頻繁に盛り上がる問題ですか?

どうすればこの問題を回避できますか?

public class RoundOffDemo { 
    public static void main(String[] args) { 
     double price = 4.35; 
     int cents = (int) (100 * price); // Should be 435 
     System.out.println(cents); // Prints 434! 
    } 
} 
+0

[浮動小数点演算がJavaで正確な結果を生成しない]の可能性重複(http://stackoverflow.com/questions/1661273/floating-point-arithmetic-not- production-exact-results-in-java)を使用します。そして少なくとも100の他の質問。 – dan04

答えて

7

問題は、4.35を2進数で正確に表すことができないことです。したがって、4.35 * 100は正確に435.0ではありません。残念ながら、0.35小数点は、非終端の2進数の拡張を持っています。したがって、4.35は、4.349999 ... xのようになります(xは何かです)。すべてがゼロ、浮動小数点数の機械の有限表現の礼儀で、それを超える。)整数の切り捨ては、その後、あなたがこの問題を回避するためにMath.round()を使用することができます434を生成します。

+0

さらに、Math.print()がそのような場合(intへのキャスト)に使用する方が正しいと思います。 – 4ndrew

+0

@ 4ndrew - おそらくそうです。引数は 'float'にキャストされるので、' round'は 'int'を返します。 (OPが使用している数字の場合は、 'double 'の代わりに' float'を使用すると最適なオプションになるかもしれません) –

+2

"現実世界"の良い例は1/3です。小数。コンピュータがバイナリの代わりに10進数を使用する場合、1/3 * 3は1.0ではなく0.9999999になります。 – user949300

-1
  1. 代わりにBigDecimalのを使用して、Javaで浮動小数点演算のためのダブル/ floatを使用しないでください。これは、Javaが浮動小数点を正確に表現できないためです。

  2. 将来の計算で処理/関与する一時変数には常にBigDecimalを使用してください。値をfloat/doubleに変換するのは、それらをデータベースに保持する場合のみです。

+1

私は万能薬としてBigDecimalを使用しません。それは一般的に丸め問題を解決するものではありません。たとえば、除算して結果を10進数で正確に表すことができない場合は、丸めモードを指定するか、例外が発生します。しかし、丸めモードを指定することで、BigDecimalでも3 *(4/3)!= 4の問題に戻ります。 –

+1

浮動小数点数の正確な表現はJavaに継承されても問題ありません。しかしバイナリアーキテクチャ上で動作するコンピュータに固有の問題です。 – Perception

0

これは、浮動小数点演算の結果である。(int)鋳造丸め関数ではなく、むしろ@Tedが指摘する切り捨てです。

お金を扱っているので(変数名から明らかなように)、代わりにBigDecimalを使用してください。例えば

- あなたはこのコードを使用している場合

double d = 4.35; 
BigDecimal bd = BigDecimal.valueOf(d); 
bd = bd.multiply(new BigDecimal(100)); 
+1

これで問題は解決されません。 'd'は既に4.35ではないので、' bd'はこの丸め誤差を前方に伝えます。 –

+0

@Ted - 実際に試してみましたが、コードを投稿する前に正しく機能していることを確認しました。 'BigDecimal.valueOf(d)'は 'Double.toString(d)'を使い、一貫して同じ出力を生成します。私はここにいけないと仮定していますか? – Kal

+1

これのどこかで何か他のことが起こっているに違いありません。小数点4.35は2進数100.0(1011)です。浮動小数点で正確に表すことはできません。 –

0

System.out.println(price*100); // Prints 434! 

を使用すると、その出力が

434.99999999999994

WHで気づきます丸められています。434

+0

しかし、それが最初に434.99999999999994を与えるのはなぜですか?私が使った数字はその答えを与えるべきではありません。 – mino

+0

@ m92 javaは数学者ではありません。他の人は浮動小数点精度にいくつかの問題があると言います。 –

+1

@AdelBoutrosこれはJavaの問題ではありません。 – 4ndrew

2

IMO、BigDecimalを使用するための提案は過剰です。セントについては、長いものを使用してください。米国の国家債務さえも、長いセントでカバーすることができます。

float(またはdouble)を使用する場合は、整数に変換するときはMath.round()、Math.floor()またはMath.ceil()を適切に使用します。

0

倍率4.35は、実際には4.349999999999999と表されます。 100 * 4.349999999999999 = 434.9999999999999。 そして、それは価値があなたを与えるだろうint型にキャスト434

+0

4.34999999999996447286321199499070644378662109375正確には – dan04