2017-08-03 93 views
0

我正在寫一個程序,它從數據庫中取出原始的double值並將它們轉換爲8字節的十六進制字符串,但我不知道如何防止精度損失。從所有設備收到的數據都以雙精度存儲,包括8字節的標識值。雙打如何避免Java中出現雙精度損失?

實例如7.2340172821234e + 16解析正確的沒有精度,其中指數是10^16損失。

但是,在指數爲10^17的情況下,Java會失去精度。 例如,2.88512954935019e + 17由爪哇解釋爲1.44464854248327008E17

代碼我使用看起來像這樣:

public Foo(double bar) { 
    this.barString = Long.toHexString((long) bar); 
    if (barString.length == 15) { 
     barString = "0" + barString; //to account for leading zeroes lost on data entry 
    } 
} 

我使用一個類似的測試用例來測試它:

@Test 
public void testFooConstructor() { 
    OtherClass other = new OtherClass(); 

    OtherClass.Foo test0 = other.new Foo(72340172821234000d); //7.2340172821234e+16 
    assertEquals("0101010100000150", test0.barString); //This test passes 

    OtherClass.Foo test1 = other.new Foo(144464854248327000d);//1.44464854248327e+17 
    assertEquals("02013e0500000758, test1.barString); //This test fails 
} 

單元測試狀態:

Expected: 02013e0500000758 
Actual: 02013e0500000760 

當I p RINT指出,Java存儲72340172821234000d和144464854248327000d因爲它分別打印的值:

7.2340172821234E16

1.44464854248327008E17

後者值是關閉的8,這似乎是爲一貫很少有我測試過。

有什麼我可以改正這個錯誤嗎?

編輯:這不是我關心的是過去的那些地方有問題。有些人認爲這是重複的問題是問爲什麼浮點數不夠精確,我正在問如何通過與Roman Puchkovskiy建議的類似的解決方法來避免精度損失。

+1

你不能。 'double'的精確度有限。 –

+0

嘗試使用BigDecimal – DwB

+0

@DwB或者,如果它是一個整數BigInteger。 – Dukeling

回答

2

你可以從數據庫中把你的浮點值的字符串(而不是浮動點),然後使用BigDecimal將它們轉換爲long

String fpAsString = getFromDB(); 
long longValue = new BigDecimal(fpAsString).longValue(); 
this.barString = Long.toHexString(longValue); 

BigDecimal .longValue()類似於從基本收縮轉換doublelong,但它不會失去精度(除了小數部分的損失)。如果結果不符合long,則可能會丟失某些東西,但投射到long時也會發生同樣的情況。

0

float和double類型的變量用於存儲任何非常大的數字或非常小的數字,但非常不好用大量的數字存儲號碼,這是非常好的,因爲它們的二進制表示。

基本上如果考慮看看如何雙人或浮動存儲在存儲器中,也有符號一位,對指數和若干位爲小數幾個位。

所以看的價值實際上是如何存儲在存儲器中時,它是這樣的:

bits

和實際值的計算公式如下:

formula

(這個例子指的是用32位表示的Float,用64位表示雙精度但適用相同的原理)

數字可以表示的位數限於小數部分可以表示的位數,但即使數字非常有限,雙數和浮點數也可以通過使用指數表示非常大的數字和非常小的數字。

在java double中,小數部分取52位,如果您要在計算器中檢查52位數字最大的數字是什麼(formula2),您將看到您將得到一個16位數字。在使用指數所表示的數字之前或之後,Double可以表示比在零之前或之後添加零的數字更大的數字,但它不能存儲具有超過16位數字而不會丟失精度的數字。

注意,實際上還有更多,這只是Double和Float表示的一個非常基本的解釋。 如果你想深入更準確的解釋,你可以檢查這個維基百科頁面:https://en.wikipedia.org/wiki/Single-precision_floating-point_format