114

私はプリミティブフロートを持っていて、プリミティブダブルとして必要です。float を double にキャストするだけで、奇妙な追加の精度が得られます。例えば:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

ただし、キャストする代わりに float を文字列として出力し、文字列を double として解析すると、必要なものが得られます。

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

String に行って戻るよりも良い方法はありますか?

4

10 に答える 10

134

実際に余分な精度が得られているわけではありません。最初に目指していた数値を float が正確に表していなかったということです。double元のフロートを正確に表しています。toStringすでに存在していた「余分な」データを示しています。

たとえば (これらの数値は正しくありません。私はただでっち上げているだけです)、次のように仮定します。

float f = 0.1F;
double d = f;

その場合、 の値はf正確に 0.100000234523 になる可能性があります。dまったく同じ値になりますが、それを文字列に変換すると、より高い精度で正確であることが「信頼」されるため、早期に丸められず、すでにあった「余分な数字」が表示されますそこに、しかしあなたから隠されています。

文字列に変換して元に戻すと、元の float よりも文字列値に近い double 値になりますが、これは、文字列値が本当に必要なものであると本当に信じている場合にのみ有効です。

float/double が の代わりにここで使用する適切な型であると確信していますBigDecimalか? 正確な 10 進数値 (たとえば、お金) を持つ数値を使用しようとしている場合BigDecimalは、より適切な型 IMO です。

于 2009-05-27T14:42:39.413 に答える
46

バイナリ表現に変換すると、この問題を把握しやすくなります。

float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;

System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));

最後に 0 を追加することで float が double に拡張されていることがわかりますが、0.27 の double 表現は「より正確」であるため、問題が発生します。

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000
于 2012-02-07T08:45:44.683 に答える
25

これは の契約によるものでありFloat.toString(float)その一部は次のように述べられています。

小数部分は何桁表示する必要がありますか […]? 小数部分を表すには少なくとも 1 桁が必要であり、それを超える桁数は、引数値を float 型の隣接する値から一意に区別するために必要な数だけです。 つまり、x が有限の非ゼロ引数 f に対してこのメ​​ソッドによって生成された 10 進数表現によって表される正確な数学的値であるとします。その場合、f は x に最も近い float 値でなければなりません。または、2 つの float 値が x に等しく近い場合、f はそれらのいずれかであり、f の仮数の最下位ビットは 0 でなければなりません。

于 2009-05-27T14:56:04.347 に答える
16

プロジェクトが非常に巨大であるため、今日この問題に遭遇し、BigDecimal へのリファクタリングを使用できませんでした。しかし、私は使用して解決策を見つけました

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

そして、これは機能します。

result.doubleValue() を呼び出すと 5623.22998046875 が返されることに注意してください。

ただし、 doubleResult.doubleValue() を呼び出すと、正しく 5623.23 が返されます

しかし、それが正しい解決策であるかどうかは完全にはわかりません。

于 2013-01-02T12:24:55.653 に答える
7

/のBigDecimal代わりにa を使用します。2 進浮動小数点として表現できない数がたくさんあります (たとえば、)。したがって、常に結果を既知の精度に丸めるか、 を使用する必要があります。floatdouble0.1BigDecimal

詳細については、 http://en.wikipedia.org/wiki/Floating_pointを参照してください。

于 2009-05-27T14:45:28.750 に答える
1

float は本質的に不正確であり、常にきれいな丸めの「問題」があります。精度が重要な場合は、Decimal または BigDecimal を使用するようにアプリケーションをリファクタリングすることを検討してください。

はい、オン プロセッサがサポートされているため、浮動小数点数は 10 進数よりも計算が高速です。ただし、高速または正確が必要ですか?

于 2009-05-27T14:55:36.220 に答える
0

これは機能しますか?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;
于 2016-03-04T12:18:15.543 に答える