BigDecimal用法詳解
* Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數進行精確的運算。
* 雙精度浮點型變量double可以處理16位有效數。在實際應用中,需要對更大或者更小的數進行運算和處理。
* float和double只能用來做科學計算或者是工程計算,在商業計算中要用java.math.BigDecimal。
* BigDecimal所創建的是對象,我們不能使用傳統的+、-、*、/等算術運算符直接對其對象進行數學運算,而必須調用其相對應的方法。方法中的參數也必須是BigDecimal的對象。
* 構造器是類的特殊方法,專門用來創建對象,特別是帶有參數的對象。
1.構造器描述
BigDecimal(int) 創建一個具有參數所指定整數值的對象。
BigDecimal(double) 創建一個具有參數所指定雙精度值的對象。(不建議采用)
BigDecimal(long) 創建一個具有參數所指定長整數值的對象。
BigDecimal(String) 創建一個具有參數所指定以字符串表示的數值的對象。
* 為什么不建議采用第二種構造方法?
a.有人可能認為在Java中寫入newBigDecimal(0.1)所創建的BigDecimal正好等於 0.1(非標度值 1,其標度為 1),但是它實際上等於0.1000000000000000055511151231257827021181583404541015625。
b.計算機是二進制的。浮點數沒有辦法是用二進制進行精確表示。我們的CPU表示浮點數由兩個部分組成:指數和尾數,這樣的表示方法一般都會失去一定的精確度,有些浮點數運算也會產生一定的誤差。
c.可以先將Double型轉換成String型,使用String構造方法。
2.方法描述
add(BigDecimal) BigDecimal對象中的值相加,然后返回這個對象。
subtract(BigDecimal) BigDecimal對象中的值相減,然后返回這個對象。
multiply(BigDecimal) BigDecimal對象中的值相乘,然后返回這個對象。
divide(BigDecimal) BigDecimal對象中的值相除,然后返回這個對象。
abs() BigDecimal對象中的值取絕對值,然后返回這個對象。
toString() 將BigDecimal對象的數值轉換成字符串。
doubleValue() 將BigDecimal對象中的值以雙精度數返回。
floatValue() 將BigDecimal對象中的值以單精度數返回。
longValue() 將BigDecimal對象中的值以長整數返回。
intValue() 將BigDecimal對象中的值以整數返回。
這里有一點需要注意的是除法運算divide.
BigDecimal除法可能出現不能整除的情況,比如 4.5/1.3,
這時會報錯java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
其實divide方法有可以傳三個參數
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
第一參數表示除數, 第二個參數表示小數點后保留位數,
第三個參數表示舍入模式,只有在作除法運算或四舍五入時才用到舍入模式,有下面這幾種
ROUND_UP //向遠離0的方向舍入;在丟棄非零部分之前始終增加數字(始終對非零舍棄部分前面的數字加1)。
ROUND_DOWN //向零方向舍入;在丟棄某部分之前始終不增加數字(從不對舍棄部分前面的數字加1,即截短)。
ROUND_CEILING //向正無窮方向舍入;如果 BigDecimal 為正,則舍入行為與 ROUND_UP 相同; 如果為負,則舍入行為與 ROUND_DOWN 相同。
ROUND_FLOOR //向負無窮方向舍入;如果 BigDecimal 為正,則舍入行為與 ROUND_DOWN 相同;如果為負,則舍入行為與 ROUND_UP 相同。
ROUND_HALF_UP //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向上舍入, 1.55保留一位小數結果為1.6
ROUND_HALF_DOWN //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入, 例如1.55 保留一位小數結果為1.5
ROUND_HALF_EVEN //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,如果保留位數是奇數,使用ROUND_HALF_UP,如果是偶數,使用ROUND_HALF_DOWN
ROUND_UNNECESSARY //計算結果是精確的,不需要舍入模式
按照各自的需要,可傳入合適的第三個參數。四舍五入采用 ROUND_HALF_UP
需要對BigDecimal進行截斷和四舍五入可用setScale方法,例:
public static void main(String[] args) { BigDecimal a = new BigDecimal("4.5635"); a = a.setScale(3, RoundingMode.HALF_UP); //保留3位小數,且四舍五入 System.out.println(a);
}
加減乘除其實最終都返回的是一個新的BigDecimal對象,因為BigInteger與BigDecimal都是不可變的(immutable)的,在進行每一步運算時,都會產生一個新的對象
public static void main(String[] args) { BigDecimal a = new BigDecimal("4.5"); BigDecimal b = new BigDecimal("1.5"); a.add(b); System.out.println(a); //輸出4.5. 加減乘除方法會返回一個新的BigDecimal對象,原來的a不變
}
3.格式化及例子
由於NumberFormat類的format()方法可以使用BigDecimal對象作為其參數,可以利用BigDecimal對超出16位有效數字的貨幣值,百分值,以及一般數值進行格式化控制。
以利用BigDecimal對貨幣和百分比格式化為例。首先,創建BigDecimal對象,進行BigDecimal的算術運算后,分別建立對貨幣和百分比格式化的引用,最后利用BigDecimal對象作為format()方法的參數,輸出其格式化的貨幣值和百分比。
public static void main(String[] args) { NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立貨幣格式化引用
NumberFormat percent = NumberFormat.getPercentInstance(); //建立百分比格式化引用
percent.setMaximumFractionDigits(3); //百分比小數點最多3位
BigDecimal loanAmount = new BigDecimal("15000.48"); //貸款金額
BigDecimal interestRate = new BigDecimal("0.008"); //利率
BigDecimal interest = loanAmount.multiply(interestRate); //相乘
System.out.println("貸款金額:\t" + currency.format(loanAmount)); System.out.println("利率:\t" + percent.format(interestRate)); System.out.println("利息:\t" + currency.format(interest)); } 運行結果如下: 貸款金額: ¥15,000.48 利率: 0.8% 利息: ¥120.00
4. BigDecimal比較
BigDecimal是通過使用compareTo(BigDecimal)來比較的,具體比較情況如下:
public static void main(String[] args) { BigDecimal a = new BigDecimal("1"); BigDecimal b = new BigDecimal("2"); BigDecimal c = new BigDecimal("1"); int result1 = a.compareTo(b); int result2 = a.compareTo(c); int result3 = b.compareTo(a); System.out.println(result1); System.out.println(result2); System.out.println(result3); }
打印結果是:-1、0、1,即左邊比右邊數大,返回1,相等返回0,比右邊小返回-1。
注意不能使用equals方法來比較大小。
使用BigDecimal的壞處是性能比double和float差,在處理龐大,復雜的運算時尤為明顯,因根據實際需求決定使用哪種類型。
5.總結
(1)商業計算使用BigDecimal。
(2)盡量使用參數類型為String的構造函數。
(3) BigDecimal都是不可變的(immutable)的,在進行每一步運算時,都會產生一個新的對象,所以在做加減乘除運算時千萬要保存操作后的值。