讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議22:用整數類型處理貨幣 >

建議22:用整數類型處理貨幣

在日常生活中,最容易接觸到的小數就是貨幣,比如你付給售貨員10元錢購買一個9.60元的零食,售貨員應該找你0.4元也就是4毛錢才對,我們來看下面的程序:


public class Client{

public static void main(Stringargs){

System.out.println(10.00-9.60);

}

}


我們期望的結果是0.4,也應該是這個數字,但是打印出來的卻是0.40000000000000036,這是為什麼呢?

這是因為在計算機中浮點數有可能(注意是可能)是不準確的,它只能無限接近準確值,而不能完全精確。為什麼會如此呢?這是由浮點數的存儲規則所決定的,我們先來看0.4這個十進制小數如何轉換成二進制小數,使用「乘2取整,順序排列」法(不懂?這就沒招了,太基礎了),我們發現0.4不能使用二進制準確的表示,在二進制數世界裡它是一個無限循環的小數,也就是說,「展示」都不能「展示」,更別說是在內存中存儲了(浮點數的存儲包括三部分:符號位、指數位、尾數,具體不再介紹),可以這樣理解,在十進制的世界裡沒有辦法準確表示1/3,那在二進制世界裡當然也無法準確表示1/5(如果二進制也有分數的話倒是可以表示),在二進制的世界裡1/5是一個無限循環小數。

各位要說了,那我對結果取整不就對了嗎?代碼如下:


public class Client{

public static void main(Stringargs){

NumberFormat f=new DecimalFormat("#.##");

System.out.println(f.format(10.00-9.60));

}

}


打印出結果是0.4,看似解決了,但是隱藏了一個很深的問題。我們來思考一下金融行業的計算方法,會計系統一般記錄小數點後的4位小數,但是在匯總、展現、報表中,則只記錄小數點後的2位小數,如果使用浮點數來計算貨幣,想想看,在大批量的加減乘除後結果會有多大的差距(其中還涉及後面會講到的四捨五入問題)!會計系統要的就是準確,但是卻因為計算機的緣故不準確了,那真是罪過。要解決此問題有兩種方法:

(1)使用BigDecimal

BigDecimal是專門為彌補浮點數無法精確計算的缺憾而設計的類,並且它本身也提供了加減乘除的常用數學算法。特別是與數據庫Decimal類型的字段映射時,BigDecimal是最優的解決方案。

(2)使用整型

把參與運算的值擴大100倍,並轉變為整型,然後在展現時再縮小100倍,這樣處理的好處是計算簡單、準確,一般在非金融行業(如零售行業)應用較多。此方法還會用於某些零售POS機,它們的輸入和輸出全部是整數,那運算就更簡單。