此次在APP開發中我遇到了精確計算問題.好比服務器給我一個百分比,我根據這個比例計算出價格,送到服務器.好比:2100.05 * 0.2計算的結果並非420.01,而是420.010000000005.在《Java解惑》這本書中有2.00 - 1.10不是0.9而是0.899999999999999.緣由是1.1 這個數字不能被精確表示成爲一個double,所以它被表示成爲最接近它的double值。二進制浮點對於貨幣計算是很是不適合的,由於它不可能將0.1——或者10的其它任何次負冪——精確表示爲一個長度有限的二進制小數.也就是計算機不認識十分之一,就像咱們10進制不認識三分之一同樣.書中給出了其中的一些解決方法,好比儘可能將將單位縮小,將」元」換成分,避免有float或者double類型的計算.但是正如我碰到的這個問題是沒有辦法避免的(關鍵是需求經理不讓改),那就只能使用BigDecimal來進行計算.下面就具體說一說BigDecimal的使用方式.html
使用BigDecimal,首先就須要構造一個BigDecimal.
好比咱們計算2.00 + 1.10java
BigDecimal bstr1 = new BigDecimal(「2.00」);
BigDecimal bstr2 = new BigDecimal(「1.10」);
BigDecimal bstr3 = null;
//表示二者相加:
bstr3 = bstr1.add(bstr2);
在這裏推薦使用BigDecimal(String)構造器,而千萬不要用BigDecimal(double)。後一個構造器將用它的參數的「精確」值來建立一個實例:new BigDecimal(.1)將返回一個表示0.100000000000000055511151231257827021181583404541015625 的BigDecimal.
若是咱們想再次賦值給一個int,long,float,double.使用對應的方法便可,如:
float f1;
int i1;
f1 = bstr3.floatValue();
i1 = bstr3.intValue();
//表示二者相減:
bstr3 = bstr1.subtract(bstr2);
//表示二者相乘:
bstr3 = bstr1.multiply(bstr2);
//表示二者相除:
bstr3 = bstr1.divide(bstr2);
在除法這邊須要注意一點,當不能整除的時候會拋出異常
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
這個時候咱們須要設置精度
bstr3 = bstr1.divide(bstr2, 2, RoundingMode.HALF_UP);
後面這個RoundingMode.HALF_UP表示四捨五入,能夠不用加可是最好是加上,否則仍是會出現一下計算上的問題.
CEILING 向正無限大方向舍入的舍入模式
DOWN 向零方向舍入的舍入模式
FLOOR 向負無限大方向舍入的舍入模式
HALF_DOWN 向最接近數字方向舍入的舍入模式,若是與兩個相鄰數字的距離相等,則向下舍入
HALF_EVEN 向最接近數字方向舍入的舍入模式,若是與兩個相鄰數字的距離相等,則向相鄰的偶數舍入
HALF_UP 向最接近數字方向舍入的舍入模式,若是與兩個相鄰數字的距離相等,則向上舍入
UNNECESSARY 用於斷言請求的操做具備精確結果的舍入模式,所以不須要舍入
UP 遠離零方向舍入的舍入模式.
你們能夠自行看看下面這邊表達是計算的是什麼?
bstr3 = bstr1.subtract(bstr2).divide(bstr2,2)服務器
咱們還可使用BigDecimal來比較大小.例如,咱們比較bstr1和bstr2
bstr1.compareTo(bstr2);
當bstr1 > bstr2時返回1
當bstr1 < bstr2時返回-1
當bstr1 = bstr2時返回0ide
小結一下:
BigDecimal的構造器有
建立一個具備參數所指定整數值的對象。
BigDecimal(int)
建立一個具備參數所指定雙精度值的對象。
BigDecimal(long)
建立一個具備參數所指定以字符串表示的數值的對象
BigDecimal(double)
建立一個具備參數所指定長整數值的對象。
BigDecimal(String)spa
方法描述
BigDecimal對象中的值相加,而後返回這個對象。
add(BigDecimal)
BigDecimal對象中的值相減,而後返回這個對象。
subtract(BigDecimal)
BigDecimal對象中的值相乘,而後返回這個對象。
multiply(BigDecimal)
BigDecimal對象中的值相除,而後返回這個對象。
divide(BigDecimal).net
將BigDecimal對象中的值以整數返回。
intValue()
將BigDecimal對象中的值以長整數返回。
longValue()
將BigDecimal對象中的值以雙精度數返回。
doubleValue()
將BigDecimal對象中的值以單精度數返回。
floatValue()
將BigDecimal對象的數值轉換成字符串。
toString()orm
上面介紹過在兩個BigDecimal相除時能夠設置精度,而且進行設置舍入的方式.
而加減乘卻沒有相應的方法,因此咱們須要調用另外一個方法setScale()htm
保留2位小數進行四捨五入.
bstr3.setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal.ROUND_HALF_UP有多種常量和上面的一致.
setScale(2)表示保留兩位位小數,默認用四捨五入方式
setScale(2,BigDecimal.ROUND_DOWN)直接刪除多餘的小數位,如1.188會變成1.18
setScale(2,BigDecimal.ROUND_UP)進1處理,1.181變成1.19
setScale(2,BigDecimal.ROUND_HALF_UP)四捨五入,1.188變成1.19
setScaler(2,BigDecimal.ROUND_HALF_DOWN)應該叫五舍六入,1.355變成1.35,1.356變成1.36
經常使用是這幾個,不過舍入的模式總共八種其餘的有須要的能夠了解一下.對象
補充一個格式化的方法NumberFormat.
//創建貨幣格式化引用
NumberFormat formatCurrency = NumberFormat.getCurrencyInstance();
//創建百分比格式化引用
NumberFormat formatpPercent = NumberFormat.getPercentInstance();blog
formatCurrency.format(「0.02」)
這樣雖然代碼中沒有提示錯誤,可是運行時會報:Caused by: java.lang.IllegalArgumentException: Bad class: class java.lang.String
因此參數不要用String,能夠是BigDecimal類型的.
formatCurrency.format(200)
結果是
¥200
參考文章:
http://www.cnblogs.com/linjiqin/p/3413894.html
http://blog.csdn.net/daryl715/article/details/1604174
http://www.bdqn.cn/news/201311/11834.shtml 《java解惑》