2015-06-11 18 views
8

我正在使用jdk 1.8.0_45,並且我們的測試發現了路由中的一個錯誤。 RoundingMode.HALF_DOWN的工作方式相同RoundingMode.HALF_UP當決定舍入的最後一位小數是5Java8中的RoundingMode.HALF_DOWN問題

我發現相關問題與RoundingMode.HALF_UP,但它們固定在更新40.我也把錯誤的oracle,但從我的經驗來看,他們確實沒有反應。

package testjava8; 

import java.math.RoundingMode; 
import java.text.DecimalFormat; 

public class Formatori { 

    public static void main(String[] args) { 
     DecimalFormat format = new DecimalFormat("#,##0.0000"); 
     format.setRoundingMode(RoundingMode.HALF_DOWN); 
     Double toFormat = 10.55555; 
     System.out.println("Round down"); 
     System.out.println(format.format(toFormat)); 

     format.setRoundingMode(RoundingMode.HALF_UP); 
     toFormat = 10.55555; 
     System.out.println("Round up"); 
     System.out.println(format.format(toFormat)); 
    } 
} 

實際結果: 回合下來 10.5556 四捨五入 10.5556

預期結果(獲得與JDK 1.7): 回合下來 10.5555 四捨五入 10.5556

+2

該錯誤不能用jdk 1.8.0_45重現。我讀到你說的問題,但不是同一個問題。這個問題已經解決。 – cristi

回答

10

看來,這是意圖改變。 JDK 1.7的行爲不正確。

問題是,你只需要不能代表類型的號碼10.55555。它以IEEE二進制格式存儲數據,所以當您將小數點10.55555編號分配給double變量時,實際上會得到最接近的值,可以用IEEE格式表示:10.555550000000000210320649784989655017852783203125。該數字大於10.55555,因此在HALF_DOWN模式下正確舍入爲10.5556

您可以檢查一些可以用二進制精確表示的數字。例如,10.15625(這是10 + 5/32,因此1010.00101二進制)。該數字在HALF_DOWN模式下取整爲10.1562,在HALF_UP模式下取樣爲10.1563

如果你想恢復舊行爲,可以先你的電話號碼轉換爲BigDecimal使用BigDecimal.valueOf構造函數,它「翻譯一個doubleBigDecimal,使用double的規範化字符串表示形式」:

BigDecimal toFormat = BigDecimal.valueOf(10.55555); 
System.out.println("Round down"); 
System.out.println(format.format(toFormat)); // 10.5555 

format.setRoundingMode(RoundingMode.HALF_UP); 
toFormat = BigDecimal.valueOf(10.55555); 
System.out.println("Round up"); 
System.out.println(format.format(toFormat)); // 10.5556 
+0

請注意,Java允許在數字文字中使用下劃線。使用它們來標記四捨五入點可以幫助讀者通過一堆'5'... – Holger

+1

我正要發佈類似的答案,因爲行爲似乎對我來說是正確的。這將是問題[JDK-7131459](https://bugs.openjdk.java.net/browse/JDK-7131459)。然而,它似乎應該[回到7u40](https://bugs.openjdk.java.net/browse/JDK-8000978),爲什麼它會發生在7u80?或者也許這是一個不同的錯誤? –

+1

DecimalFormat類不會說它是否會在double的精確表示或標準表示(除非我錯過了它),因此兩種行爲都可以接受... – assylias

5

行爲的變化在the release notes of Java 8

是記錄當使用NumberFormatDecimalFormat類,滾裝JDK以前版本的錯誤行爲在某些特定情況下是錯誤的。 [...]

作爲一個例子,使用默認時,建議NumberFormatFormat API形式:接着nf.format(0.8055d)NumberFormat nf = java.text.NumberFormat.getInstance(),值0.8055d被記錄在計算機作爲0.80549999999999999378275106209912337362766265869140625因爲該值不能被精確以二進制格式表示。這裏,默認的舍入規則是「half-even」,並且在JDK 7中調用format()的結果是錯誤的輸出「0.806」,而正確的結果是「0.805」,因爲在內存中由計算機在領帶的「下方」。

此新行爲也適用於可能由程序員選擇的任何模式(非默認模式)定義的所有舍入位置。