1. 程式人生 > >new BigDecimal(0.01) 與 new BigDecimal(String.valueOf(0.01))的區別 (轉)

new BigDecimal(0.01) 與 new BigDecimal(String.valueOf(0.01))的區別 (轉)

賬單 rto sta egerp 存在 調整 nan com mod

轉自:http://blog.csdn.net/major1985/article/details/50210293

一般我們使用BigDecimal進行比較精密的計算,我這裏計算金額。註意使用double構造器的本質與String構造的本質,避免造成問題。

我這裏出現的問題是金額總是多了0.01

問題出現在這段代碼:

if(valueDiffDays > 0){
            logger.info("該賬單{}需要繳納{}天利息",loanBillLogDO.getBillSeqNo(),valueDiffDays);
            interestAmt = repayAmt * interestDayRate * valueDiffDays;
            loanBillLogDO.setInterestAmt(
new BigDecimal(interestAmt).setScale(2, RoundingMode.UP)); }

應該是0.80的總是變成0.81,進行斷點調試發現interestAmt的值是0.8.

進行測試:

 @Test
    public void testBigDecimalMode(){
        double dayRate = 0.08;
        double amt = 1000;
        int diff = 1;

        double interestAmt = amt*dayRate/100*diff;
        BigDecimal tInterestAmt 
= new BigDecimal(interestAmt).setScale(2 , RoundingMode.UP); System.out.println(interestAmt); System.out.println(tInterestAmt); BigDecimal a = new BigDecimal("0.8"); System.out.println(a.setScale(2, RoundingMode.UP)); BigDecimal b = new BigDecimal(0.8); System.
out.println(b.setScale(2 , RoundingMode.UP)); // loanBillLogDO.setInterestAmt(new BigDecimal(interestAmt).setScale(2, RoundingMode.UP)); }

基本確定BigDecimal的double構造存在問題,String構造不存在問題。

api說明:

技術分享

BigDecimal

public BigDecimal(String val)
將 BigDecimal 的字符串表示形式轉換為 BigDecimal。字符串表示形式由可選符號 + ( \u002B) 或 - ( \u002D) 組成,後跟零或多個十進制數字(“整數”)的序列,可以選擇後跟一個小數,也可以選擇後跟一個指數。
該小數由小數點以及後跟的零或更多十進制數字組成。字符串必須至少包含整數或小數部分中的一個數字。由符號、整數和小數部分組成的數字稱為有效位數。

指數由字符 e\u0065) 或 E (\u0045) 以及後跟的一個或多個十進制數字組成。指數的值必須位於 Integer.MAX_VALUE (Integer.MIN_VALUE+1) 和 Integer.MAX_VALUE(包括)之間。

更正式地說,以下語法描述了此構造方法接受的字符串:

BigDecimalString:
Signopt Significand Exponentopt
Sign:
+
-
Significand:
IntegerPart . FractionPartopt
. FractionPart
IntegerPart
IntegerPart:
Digits
FractionPart:
Digits
Exponent:
ExponentIndicator SignedInteger
ExponentIndicator:
e
E
SignedInteger:
Signopt Digits
Digits:
Digit
Digits Digit
Digit:
Character.isDigit(char) 對其返回 true 的任何字符,如 012……
返回的 BigDecimal 的標度將是小數部分中的數字位數,如果該字符串不包含小數點,則標度為零,這取決於對指數的調整;如果字符串包含一個指數,則從標度減去該指數。得到的標度值必須位於 Integer.MIN_VALUE 和 Integer.MAX_VALUE(包括)之間。

Character.digit(char, int) 集提供從字符到數字的映射,以轉換成基數 10。該字符串不能包含任何額外字符(例如,空白)。

示例:
返回的 BigDecimal 的值等於有效位數 × 10 指數。對於左邊的每個字符串,得到的表示形式 [BigInteger, scale] 顯示在右邊。

 "0"            [0,0]
 "0.00"         [0,2]
 "123"          [123,0]
 "-123"         [-123,0]
 "1.23E3"       [123,-1]
 "1.23E+3"      [123,-1]
 "12.3E+7"      [123,-6]
 "12.0"         [120,1]
 "12.3"         [123,1]
 "0.00123"      [123,5]
 "-1.23E-12"    [-123,14]
 "1234.5E-4"    [12345,5]
 "0E+7"         [0,-7]
 "-0"           [0,0]
 
註:對於不是 floatdouble NaN 和 ±Infinity 的值,此構造方法與 Float.toString(float) 和 Double.toString(double) 返回的值兼容。這通常是將 floatdouble 轉換為 BigDecimal 的首選方法,因為它不會遇到 BigDecimal(double) 構造方法的不可預知問題。

參數:
val - BigDecimal 的字符串表示形式。
拋出:
NumberFormatException - 如果 val 不是 BigDecimal 的有效表示形式。

技術分享

new BigDecimal(0.01) 與 new BigDecimal(String.valueOf(0.01))的區別 (轉)