簡體   English   中英

將 float 轉換為 double 而不會丟失精度

[英]Convert float to double without losing precision

我有一個原始浮點數,我需要一個原始雙精度數。 簡單地將浮點數轉換為 double 會給我帶來奇怪的額外精度。 例如:

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

但是,如果不是強制轉換,而是將浮點數輸出為字符串,並將字符串解析為雙精度字符串,我會得到我想要的:

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

有沒有比去字符串和返回更好的方法?

這並不是說您實際上獲得了額外的精度 - 而是浮點數沒有准確地表示您最初瞄准的數字。 雙精度表示原始浮點數; toString顯示已經存在的“額外”數據。

例如(這些數字不正確,我只是在編造)假設你有:

float f = 0.1F;
double d = f;

那么f的值可能正好是 0.100000234523。 d將具有完全相同的值,但是當您將其轉換為字符串時,它會“相信”它的精度更高,因此不會提前四舍五入,您會看到原來的“額外數字”已經在那里,但對你隱藏。

當您轉換為字符串並返回時,您最終會得到一個比原始浮點數更接近字符串值的雙精度值 - 但只有您真的相信字符串值是您真正想要的值時,這才是好的。

您確定 float/double 是在此處使用而不是BigDecimal的合適類型嗎? 如果您嘗試使用具有精確十進制值的數字(例如貨幣),那么BigDecimal是更合適的 IMO 類型。

我發現轉換為二進制表示更容易掌握這個問題。

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 將浮點數擴展為雙精度,但 0.27 的雙精度表示“更准確”,因此存在問題。

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

這是由於Float.toString(float)的合同,其中部分內容是:

小數部分 […] 必須打印多少位? 必須至少有一個數字來表示小數部分,除此之外,必須有盡可能多的數字,但僅能將參數值與浮點類型的相鄰值唯一區分開來。 也就是說,假設 x 是由該方法為有限非零參數 f 生成的十進制表示所表示的精確數學值。 那么 f 必須是最接近 x 的浮點值; 或者,如果兩個浮點值同樣接近 x,則 f 必須是其中之一,並且 f 的有效位的最低有效位必須為 0。

我今天遇到了這個問題,無法使用重構到 BigDecimal,因為該項目非常龐大。 但是我找到了解決方案

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

這有效。

注意調用 result.doubleValue() 返回 5623.22998046875

但調用 doubleResult.doubleValue() 正確返回 5623.23

但我不完全確定它是否是正確的解決方案。

我找到了以下解決方案:

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

如果您使用floatdouble而不是FloatDouble ,請使用以下內容:

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

使用BigDecimal而不是float / double 有很多數字不能表示為二進制浮點數(例如0.1 )。 因此,您要么必須始終將結果四舍五入到已知精度,要么使用BigDecimal

有關詳細信息,請參閱http://en.wikipedia.org/wiki/Floating_point

一個行之有效的簡單解決方案是從浮點數的字符串表示中解析雙精度:

double val = Double.valueOf(String.valueOf(yourFloat));

效率不高,但很有效!

浮點數本質上是不精確的,並且總是有整齊的四舍五入“問題”。 如果精度很重要,那么您可以考慮重構您的應用程序以使用 Decimal 或 BigDecimal。

是的,由於處理器支持,浮點數的計算速度比小數更快。 但是,您想要快速還是准確?

這行得通嗎?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;

有關信息,請參閱 Joshua Bloch 的 Effective Java 2nd edition 的第 48 條 - 當需要精確值時避免使用浮點數和雙精度數。 這本書塞滿了好東西,絕對值得一看。

有一種方法可以在不增加額外精度的情況下將 Float 值轉換為 Double

Float aFloat= new Float(0.11);
String s = aFloat.toString();
Double aDouble = Double.parseDouble(s);

這種方法在轉換時不會為您的浮點值增加額外的精度。 這種方法的唯一問題是通過創建額外的 tamp String 對象來使用 JVM 的內存。

在 Double 上調用 toString() (aDouble.toString()) 永遠不會增加額外的精度。 類型轉換時將添加精度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM