java.math BigDecimal類
阿新 • • 發佈:2019-02-08
雙精度浮點型變數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 類。裡面寫的很詳細了。想看的時候點進去看看。