2014-02-25 85 views
4

我試圖使用DecimalFormat來格式化雙數,只打印2位小數的數字(如果它有小數部分),否則我想按原樣打印數字。當數字很小時,下面的代碼可以正常工作,但數字很大,但它不能按預期工作。使用DecimalFormat格式化大的雙數

DecimalFormat df = new DecimalFormat("#.##"); //have tried just # too 
    double d1 = 56789d; 
    System.out.println(df.format(d1)); //works fine - prints 56789 

    double d2 = 1234567879123456789d; 
    System.out.println(df.format(d2)); // does not work 

第二輸出1234567879123456770,而我想1234567879123456789。對於帶小數部分的雙精度值,我只想保留兩位小數點。

有什麼問題的建議嗎?

+0

我懷疑你是'double''s(im)precision的受害者... – fge

回答

7

關於爲什麼解析值關閉19的說明在於如何表示double值,因爲IEEE floating-point numbers具有53位精度。也就是說,對於輸入的大數值,精度實際上大於1。方法Math.ulp,對於「最後一個單位」,給出最接近的double值可以在其論點的大小上分開。

double d2 = 1234567879123456789d; 
DecimalFormat df = new DecimalFormat("#.##"); 
System.out.println(Math.ulp(d2)); 
System.out.println(df.format(d2)); 

此輸出

256.0 
1234567879123456770 

所以,你得到的最接近double價值給你在源代碼中鍵入數字。 Section 3.10.2 of the JLS覆蓋double文字:

的類型float元素,並且是可以使用IEEE 754的32位單精度和64位雙精度二進制浮點格式來表示這些值,分別雙。

對於浮點類的方法valueOf和包java.lang的類Double,描述了從浮點數的Unicode字符串表示形式到內部IEEE 754二進制浮點表示形式的正確輸入轉換的詳細信息。

並且參照Double.valueOf javadocs

s的視爲代表在常用的「計算機科學記數法」或者是一個精確的十六進制值的精確十進制值;然後將該確切的數值概念轉換爲「無限精確」的二進制值,然後通過IEEE 754浮點運算的通常的舍入到最近的規則舍入爲double類型[012]

此外,該值仍在long值的範圍內,該值仍將正確表示整數值。

long l2 = 1234567879123456789L; 
DecimalFormat df = new DecimalFormat("#.##"); 
System.out.println(df.format(l2)); 

此輸出

1234567879123456789 
+0

感謝您的詳細解答。很多新的東西給我。 – RandomQuestion

+0

不知道ulp。很好的答案!+1 – fge

+0

邊欄問題,我們在這裏:'StrictMath'也有'ulp()'方法,這些和'Math'有區別嗎? – fge

0

你的文字有19個十進制數字,但雙只具有精度15.9小數位數。

相關問題