1. 程式人生 > >浮點數在金額計算中的使用總結

浮點數在金額計算中的使用總結

class effect sta void java 解決 clas sel 成了

浮點數在金額計算中的使用總結(摘自~~)

double 和 float 類型的變量不適合用作金額計算是java語言使用中的基本知識,但在實際應用中此基本常識經常被程序員忽視,想當然的用在了實際的金額計算場景中,造成難以察覺的錯誤。在此對金額計算的使用方法做個總結,以規範後續使用。

1. double和float 的不準確

《effective Java》中指出,float和double類型主要是為科學計算和工程計算而設計的,不應該被用於需要精確結果的場合,尤其不適合於貨幣計算,見如下代碼:

public class DoubleHandle {
    static double a = 2.0;
    static double b = 1.1;

    public static void main(String[] args){
        System.out.print("2.0 減 1.1 的double類型計算值為:");
        System.out.println((a - b));
    }
}

輸出結果為

2.0 減 1.1 的double類型計算值為:0.8999999999999999

明顯可見結果是不正確的。原因為在二進制系統中無法精確的表示10的負n次冪,如同十進制無法精確的表示1/3一樣。為了能夠解決這個問題,java提供了BigDecimal類,那麽只要使用了BigDecimal類結果就一定正確嗎?

2. BigDecimal類的錯誤使用

根據上文結論,容易犯的錯誤如下圖代碼:

public class DoubleHandle {

    static BigDecimal aBig = new BigDecimal(2.0);
    static BigDecimal bBig = new BigDecimal(1.1);

    public static void main(String[] args){
            System.out.println("2.0 減 1.1 的BigDecimal類型計算值為:"
                + String.valueOf(aBig.subtract(bBig)));
    }
}

運行結果為:

2.0 減 1.1 的BigDecimal類型計算值為:
0.899999999999999911182158029987476766109466552734375

結果仍然是錯誤的。原因為實例化BigDecimal類時,使用的是double類型的常量,那麽仍然無法避免double類型精度丟失的問題,正確的使用方式為用String類型來初始化BigDecimal類。

3. BigDecimal的正確使用

使用下面的代碼運行:

public class DoubleHandle {
    static BigDecimal aStrBig = new BigDecimal("2.0");
    static BigDecimal bStrBig = new BigDecimal("1.1");

    public static void main(String[] args){       
        System.out.println("2.0 減 1.1 的BigDecimal類型計算值為:"
                + String.valueOf(aStrBig.subtract(bStrBig)));
    }
}

運行結果為:

2.0 減 1.1 的BigDecimal類型計算值為:0.9

可見已為正確的結果。

4. BigDecimal的使用註意

BigDecimal沒有定義 +或 * 等操作符的重載,因此加法等操作要用方法來實現。需要註意的是BigDecimal在執行了運行操作後,結果值並不會覆蓋回原操作數,而是生成了新的結果值。見如下代碼:

public class DoubleHandle {   
    static BigDecimal aStrBig = new BigDecimal("2.0");
    static BigDecimal bStrBig = new BigDecimal("1.1");
    public static void main(String[] args){

            System.out.println("2.0 減 1.1 的BigDecimal類型計算值為:"
                + String.valueOf(aStrBig.subtract(bStrBig)));

        System.out.println("aStrBig值為:" + String.valueOf(aStrBig));
    }

}

運行結果為:

2.0 減 1.1 的BigDecimal類型計算值為:0.9
aStrBig值為:2.0

可見計算結果0.9並沒有保存到aStrBig中去,僅僅輸出打印後就拋棄了。原因為BigDecimal為不可變類,我們不能修改現有實例的值,對這些類型的操作將返回新的實例,因此運算生成的結果值需要定義新的變量來保存。

浮點數在金額計算中的使用總結