在項目中用Java作浮點數計算時,發現對於4.015*100這樣的計算,結果不是預料中的401.5,而是401.49999999999994。如此長的位數,對於顯示來講很不友好。java
查閱相關資料,發現緣由是:計算機中的浮點數並不能徹底精確表示。例如,對於一個double型的38414.4來講,計算機是這樣存儲它的:數組
double | 符號位1位 | 階碼11位 | 尾數52位 |
從這裏能夠看出來,主要緣由在於二進制編碼使得小數部分沒法徹底精確表示,例如0.4 = 0.25 + 0.125 + ...,只能無限接近。因此在對浮點數作計算時會產生精度偏差。性能
Java中的BigDecimal能夠支持任意精度的浮點數運算。在《Effective Java 》這本書中建議:float 和double 用來作科學計算或者是工程計算,而在商業計算中使用java.math.BigDecimal 。編碼
BigDecimal有多種構造方法,如BigDecimal(double),BigDecimal(String),須要注意的是:構造參數爲String類型時才能保證不丟失精度,由於double類型自己就是不徹底精確的。故須要寫成這樣:BigDecimal("0.02")。spa
double類型的基本運算都能在BigDecimal中找到相對應的方法。另外,BigDecimal還能夠配合NumberFormat作格式化輸出。orm
BigDecimal在作運算的時候都會生成新的BigDecimal對象,所以相對double來講會帶來更多的性能開銷。對象
那麼BigDecimal是如何作到可以表示任意精度的呢?這裏只作一個初步的分析。ci
首先看BigInteger的實現。普通的int型是32位,所以有範圍限制。BigInteger中有成員變量int[] mag,這樣變長的int數組使得表示任意大小的整數成爲可能。源碼
再看BigDecimal的實現。它的官方介紹中說,任意一個BigDecimal均可以表示爲unscaledValue × 10^-scale的形式。unscaledValue是一個任意大小的整數,在源代碼中對應BigInteger intVal這個成員變量;scale是階數,在源代碼中對應int scale這個變量。這樣就在BigInteger的基礎上獲得了BigDecimal的實現。table
更細節的內容能夠自行閱讀源碼作進一步分析。