web-dev-qa-db-ja.com

精度を失わずにfloatをdoubleに変換します

プリミティブフロートがあり、プリミティブダブルとして必要です。単純にフロートを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に戻って戻るよりも良い方法はありますか?

88
Steve Armstrong

実際余分な精度を得ているということではありません。フロートが元々目指していた数字を正確に表していないということです。 double isは、元のフロートを正確に表します。 toStringは、すでに存在していた「余分な」データを示しています。

たとえば、(これらの数値は正しくありません。単に構成しているだけです)あなたが持っていると仮定します:

float f = 0.1F;
double d = f;

その場合、fの値は正確に0.100000234523になります。 dはまったく同じ値になりますが、文字列に変換すると、それがより高い精度で正確であることを「信頼」するため、早めに四捨五入せず、既に存在していましたが、あなたからは隠されています。

文字列に変換して戻すと、元のフロートよりも文字列値に近いdouble値になります-しかし、それは良いだけですifあなたは本当に文字列値を信じていますあなたが本当に欲しかったものです。

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

113
Jon Skeet

この問題を理解するには、バイナリ表現に変換する方が簡単だと思います。

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を追加することでフロートがdoubleに展開されていることがわかりますが、0.27のdouble表現は「より正確」であるため、問題があります。

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000
33
Brecht Yperman

これは Float.toString(float) の契約によるものです。

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

24
erickson

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

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

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

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

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

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

13
Andrew

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

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

7
Aaron Digulla

私は次の解決策を見つけました:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

FloatおよびDoubleの代わりにfloatおよびdoubleを使用する場合、以下を使用します。

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}
6
GSD.Aaz

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

はい、プロセッサのサポートにより、フロートは小数よりも計算が高速です。ただし、高速または正確にしたいですか?

1
NotMe

詳細については、Joshua BlochによるEffective Java 2nd editionのItem 48-正確な値が必要な場合はfloatとdoubleを避けてください。この本は良いものが詰まったジャムで、間違いなく一見の価値があります。

0
mR_fr0g

これは機能しますか?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;
0
AesmaDiv