1. 程式人生 > >java.math BigDecimal類

java.math BigDecimal類

雙精度浮點型變數double可以處理16位有效數,但是超過16位後呢,要用什麼來表示呢?

double在做算術運算時,會出現一定的偏差,如果在一般的情況下使用倒是可以, 但如果在商業領域,如:銀行業務利息計算,商場交易等。 可能會出現不好處理的問題。

System.out.println(2- 1.1);// 結果: 0.8999999999999999

其實,我們在表示一個double的值的時候,都是不完整的, 才會導致2- 1.1 不等於0.9。

那麼? 如何解決這樣的需要高度精確度的數字計算呢?

這裡,Java提供了一個類BigDecimal。

BigDecimal類是不可變的、任意精度的有符號十進位制數物件。(

精度一般指的都是小數點後面的位數

BigDecimal由任意精度的整數非標度值 和 32 位的整數標度 (scale) 組成。(可以看他的valueof()方法)

如果為零或正數,則標度是小數點後的位數。如果為負數,則將該數的非標度值乘以 10 的負 scale 次冪。

(其實在試驗中,非標度值也可以是負數)

BigDecimal提供以下操作:算術、標度操作、舍入、比較、雜湊演算法和格式轉換。

toString()方法提供 BigDecimal 的規範表示形式。

*****文章的最後提供了八中舍入方式的詳細介紹*****

下面是各種示例:

package javamath;

import java.math.BigDecimal;
import java.math.MathContext;
import java.text.NumberFormat;

/**
 * Created by Administrator on 2018/3/13.
 */
public class BigDecimalDemo {

    //1 沒有無參構造方法, 如果沒有引數,會直接編譯錯誤。


    // 構造方法
    public static void testCon(double d1){

        BigDecimal b1 = new BigDecimal(d1);
        System.out.println("double引數的構造方法"+b1);

        //d1=2.01 的結果 :2.00 9999 9999 9999 9786 8371 7927 1969 9442 3866 271 9726 5625
        //顯然存在一定的誤差
        //所以這個方法不建議使用, 因為結果具有不可預知性,  具體原因可以參照文件解釋。
    }

    // 上面可修改為
    public static void testCon2(double d1){
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        System.out.println(b1);
    }
    // 最好使用,通過String作為引數來構造
    public static void testString(){
        BigDecimal b1 = new BigDecimal("2.111");
        System.out.println(b1);
    }

    //靜態工廠方法, 建議使用這個方法建立物件。內部存放著一些固定的物件, 可以直接使用
    //兩個引數都可以為0 ,
    public static void testValueof(long unscaledVal, int scale){
        BigDecimal b1 = BigDecimal.valueOf(unscaledVal,scale);
        System.out.println(b1);
    }

    // BigDecimal 轉化為基本資料型別
    //轉化都會導致資料丟失,不建議使用。
    public static void testXXXValue(){
        BigDecimal b1 = new BigDecimal("89.1234567890123456789");
        //轉化為雙精度,有效位是16位。
        double d1 = b1.doubleValue();
        System.out.println("雙精度:"+d1);  //雙精度:89123.45678901234    剛好16位

        // 說明這樣的轉化, 丟失了資料的精度(準確度),另外其他的XXXXValue() 方法也是如此。 要慎重使用。
        // 那麼問題來了 : 如何建立一個超過16位有效位數的數字呢? 我們都知道double 也才只有16位有效位數
        // 肯定不能作為BigDecimal引數的,
        // 所以這裡只能用String型別的引數了。

    }

    //精準加法運算
    public static void testAdd(){
        BigDecimal b1 = new BigDecimal("22.22");
        BigDecimal b2 = new BigDecimal("22.2");
        b1 = b1.add(b2);
        System.out.println("加法:"+b1);   //加法:44.42 ,   說明: 標度值 Max(b1.scale,b2.cale) 去最大的那個。
    }

    // 精準減法
    public static void testSubtract(){
        BigDecimal b1 = new BigDecimal("22.22");
        BigDecimal b2 = new BigDecimal("22.2");
        b1 = b1.subtract(b2);
        System.out.println(b1);   //0.02   說明: 標度值 Max(b1.scale,b2.cale) 去最大的那個。
    }


    // 乘法運算
    public static void testmultiply(){
        BigDecimal b1 = new BigDecimal("22.22");
        BigDecimal b2 = new BigDecimal("0.02");
        b1 = b1.multiply(b2);
        System.out.println(b1); //0.4444   說明: 標度值scale = b1.scale+ b2.scale+ .....

    }
    //除法
    public static void testDivide(){
        BigDecimal b1 = new BigDecimal(1);
        BigDecimal b2 = new BigDecimal(3);
//        b1 = b1.divide(b2);        // 1/3當無法除盡時,會報錯 ,因為沒有提供舍入模式,和標度值
        System.out.println(b1);
    }
    
    //精準除法
    public static void testDivide2(){
        BigDecimal b1 = new BigDecimal(1);
        BigDecimal b2 = new BigDecimal(3);
        b1=b1.divide(b2,8,BigDecimal.ROUND_CEILING);  //向正無限大方向舍入的舍入模式, 標度為8
        System.out.println(b1);         //0.33333334
    }

    //格式化
    //由於NumberFormat類的format()方法可以使用BigDecimal物件作為其引數,
    //可以利用BigDecimal對超出16位有效數字的貨幣值,百分值,以及一般數值進行格式化控制
    // 貨幣格式, 百分比
    public static void testFormat(){
        BigDecimal b1 = new BigDecimal("12345678901244442.46666");
        BigDecimal b2 = new BigDecimal(100);
        BigDecimal b1In = b1.multiply(b2);
        //貨幣格式化引用
        NumberFormat  c = NumberFormat.getCurrencyInstance();
        //建立百分比引用
        NumberFormat p = NumberFormat.getPercentInstance();
        p.setMaximumFractionDigits(3);              //  設定百分比小數點最多3位數

        System.out.println("b1In:"+b1In);
        System.out.println("貨幣格式:"+c.format(b1));   //¥12,345,678,901,244,442.47 多次測試後小數點後面固定兩位。

        System.out.println("百分比格式:"+p.format(b1));


    }


    public static void main(String[] args) {

//        testSubtract();
        testValueof(-1,1);
    }


}

舍入模式 : 這個只在除法運算中才會用到。

Java提供了一個列舉類來存放這些舍入模式。RoundingMode 類。裡面寫的很詳細了。想看的時候點進去看看。