web-dev-qa-db-ja.com

JavaでPloatを解析する正しい方法は何ですか?

Java float精度に関するいくつかの問題に気づきました

       Float.parseFloat("0.0065") - 0.001  // 0.0055000000134110451
       new Float("0.027") - 0.001          // 0.02600000000700354575
       Float.valueOf("0.074") - 0.001      // 0.07399999999999999999

Floatだけでなく、Doubleにも問題があります。

誰かが舞台裏で何が起こっているのか説明できますか、そしてどうすれば正確な数を得ることができますか?これらの問題に対処するときにこれを処理する正しい方法は何でしょうか?

9
peter

問題は、floatの精度が有限であるということです。 0.0065を正確に表すことはできません。 (もちろん、doubleについても同じことが言えます。精度は高くなりますが、それでも有限です。)

上記の問題をより明白にする別の問題は、0.001doubleではなくfloatであるため、floatがに昇格することです。減算を実行するためのdouble、そしてもちろんその時点で、システムはdoublecouldが最初に表した欠落した精度を回復する方法がありません。これに対処するには、次のように記述します。

float f = Float.parseFloat("0.0065") - 0.001f;

0.001fの代わりに0.001を使用します。

30
ruakh

すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと を参照してください。あなたの結果は私には正しいように見えます。

浮動小数点数の動作が気に入らない場合は、代わりに BigDecimal のようにしてみてください。

6
willglynn

あなたは正しい結果を得ています。 0.027のようなfloatは正確には存在せず、またそのようなdoubleも存在しません。 floatまたはdoubleを使用すると、常にこれらのエラーが発生します。

floatdoubleは次のように格納されます2進小数:1/2 + 1/4 +1/16のようなもの...すべての10進値を取得することはできません有限精度の2進小数として正確に格納されます。数学的には不可能です。

唯一の代替方法は、BigDecimalを使用することです。これを使用して、正確な10進値を取得できます。

5
Louis Wasserman

プリミティブデータ型のJavaチュートリアルページ から:

浮動小数点リテラルは、文字Fまたはfで終わる場合、float型になります。それ以外の場合、そのタイプはdoubleであり、オプションで文字Dまたはdで終了できます。

だから私はあなたのリテラルだと思います(0.001)はdoubleであり、floatからdoubleを減算しています。

代わりにこれを試してください:

System.out.println((0.0065F - 0.001D)); // 0.005500000134110451
System.out.println((0.0065F - 0.001F)); // 0.0055

...そしてあなたは得るでしょう:

0.005500000134110451
0.0055

したがって、リテラルにFサフィックスを追加すると、より良い結果が得られるはずです。

Float.parseFloat("0.0065") - 0.001F
new Float("0.027") - 0.001F
Float.valueOf("0.074") - 0.001F
4

Floatを文字列に変換してから、BigDecimalを使用します。

This リンクはそれをよく説明しています

new BigDecimal(String.valueOf(yourDoubleValue));

ただし、エラーが発生するため、BigDecimaldoubleコンストラクターは使用しないでください。

3
RNJ

任意精度が必要な場合は、floatまたはdoubleではなくBigDecimalを使用してください。 floatを使用すると、この種のあらゆる種類の丸めの問題が発生します。

余談ですが、BigDecimalのfloat/doubleコンストラクターは同じ問題が発生するため、使用しないように十分に注意してください。代わりにStringコンストラクターを使用してください。

1
Mike Q

浮動小数点は10進数を正確に表すことができません。 Javaで数値を正確に表現する必要がある場合は、Java.math.BigDecimalクラスを使用する必要があります。

BigDecimal d = new BigDecimal("0.0065");
1
Brigham