Java-從Double類型精度丟失認識BigDecimal

Java-從Double類型精度丟失認識BigDecimal

參考資料

Double類型丟失精度

public static void main(String[] args) {
    double value = 0.05 + 0.01;
    System.out.println(value);
    //0.060000000000000005
}

double 類型的 0.05 + 0.01 的結果咱們猜測的應該是 0.06 可是程序的數據結果倒是大大的超出了咱們的預料(咱們稱這種現象爲精度丟失),形成上面的這種狀況的緣由是小數在計算機中的存儲形式形成的。html

精度丟失的緣由不是本篇博客的主要內容,因此在這裏再也不贅述,想要了解的能夠查看,文章頂部的 IEEE 754 的規範。java

double 類型存在着上面的這種問題,因此咱們確定是不能用它來進行特別精細的計算了,好比 科學研究金融 相關的業務邏輯。由於一旦數據不精確就可能形成比較嚴重的問題。api

BigDecimal

既然出現了上面的這種問題,確定是有解決辦法的,官方提供的解決辦法就是 BigDecimal 類。oracle

與BigDecimal相似的還有BigInteger類.ide

構造BitDecimal

Snag_b0edd2

具備char[]參數的構造方法咱們通常是不會去主動調用的,由於當咱們調用具備string參數的構造函數時,會間接地調用char[]參數的構造方法。函數

public BigDecimal(String val) {
    this(val.toCharArray(), 0, val.length());
}

在構建BigDecimal的時候推薦使用String參數的構造方法,由於double參數的構造方法會會出現一些問題。this

public static void main(String[] args) {
    BigDecimal bigDecimal = new BigDecimal(0.06);
    System.out.println(bigDecimal);
    
    BigDecimal bigDecimalStr = new BigDecimal("0.06");
    System.out.println(bigDecimalStr);
}

輸出結果以下code

0.059999999999999997779553950749686919152736663818359375
0.06

經過輸出結果咱們發現,當經過double參數的構造方法的來建立BigDecimal對象的時候,輸出結果更加的讓人頭大了 😠。形成這樣的狀況的緣由是:htm

Snag_c392f4

官方文檔提到了像 0.一、0.06 這樣的double類型的數,不是一個精確的數值,因此形成了上面的這種狀況。而官方文檔也推薦了使用string參數的構造方法來構造 BigDecimal對象來避免這種問題。對象

強大的BigDecimal

public static void main(String[] args) {
    BigDecimal bd1 = new BigDecimal("0.5");
    BigDecimal bdResult = bd1.add(new BigDecimal("0.1"));
    System.out.println(bdResult.toString());
}

經過BigDecimal咱們就能夠避免掉,精度就是形成的數據錯誤達的問題了,然而BigDecimal不單單能夠用來解決精度就是的問題,double類型能夠作到的BigDecimal類型一樣能夠作到(如:四則運算);而BigDecimal能夠進行精度的舍入(保留兩位小數等)功能則是double 類型作不具有的。

四則運算

運算 方法
加法 bd1.add
減法 bd1.subtract
乘法 bd1.multiply
除法 bd1.divide
取模/取餘數 bd1.remainder

比較運算

經過BigDecimal對象能夠實現比較大小和判斷是否相等的功能。

public static void main(String[] args) {
    BigDecimal bd1 = new BigDecimal("0.5");
    System.out.println(bd1.compareTo(new BigDecimal("0.5")));
    System.out.println(bd1.compareTo(new BigDecimal("0.1")));
    System.out.println(bd1.compareTo(new BigDecimal("0.6")));
}
/*
輸出結果:
0
1
-1
*/

控制精度

對精度的控制體如今保留小數上,咱們能夠經過BigDecimal.scale()方法來對精度進行控制,好比四捨五入保留兩位小數等。

public static void main(String[] args) {
    //四捨五入保留兩位小數
    BigDecimal bigDecimal = new BigDecimal("2.555");
    bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
    System.out.println(bigDecimal.toString());
    //向上取整
    bigDecimal = bigDecimal.setScale(0, RoundingMode.CEILING);
    System.out.println(bigDecimal);
    //向下取整
    bigDecimal = new BigDecimal("2.1");
    bigDecimal = bigDecimal.setScale(0, RoundingMode.FLOOR);
    System.out.println(bigDecimal.toString());
}
//輸出結果
/**
2.56
3
2
*/

注意

BigDecimal是不可變的,因此每一次操做都會建立一個新的BigDecimal對象。

相關文章
相關標籤/搜索