Float和double丟失精度問題及解決方案


出現這種結果的原因:float和double類型尤其不適合用於貨幣運算,因為要讓一個float或double精確的表示0.1或者任何其他負數次方值是不可能的(十進制系統中不能准確的表示出1/3,同樣二進制系統也不能准確的表示1/10)。

1.十進制整數轉為二進制數:

例子:11表示成二進制數:

11/2 =5 余1

5/2 = 2 余1

2/2 = 1 余0

1/2 = 0 余1

0結束,11二進制表示為(從下往上):1011

注意:只要遇到除以后的結果為0就結束了。所有的整數除以2一定能夠最終得到0,但是小數就不能,小數轉變為二進制的算法就有可能會無限循環下去。

2.十進制小數轉為二進制數

算法是乘以2知道沒有了小數為止,例子:

0.9表示成二進制數:

0.9*2 = 1.8 取整數部分:1

0.8*2 = 1.6 取整數部分:1

0.6*2 = 1.2 取整數:1

0.2*2 = 0.4 取整數:0

0.4*2 = 0.8 取整數:0

0.8*2 = 1.6 取整數:1

。。。。

0.9二進制表示為(從上往下):1100100100100.......

注意:上面的計算過程循環了,也就是說乘以2永遠不能消滅小數部分,這樣算法將無限下去。顯然,小數的二進制表示有時是不能精確的。道理很簡單,十進制系統中不能准確的表示出1/3,同樣二進制也無法准確的表示1/10。這也是浮點型出現精度丟失問題的主要原因。

解決方案一:

如果不介意記錄十進制的小數點,而且數值不大,那么可以使用long,int等基本類型,

int resultInt = 10 -9;

double result  = (double)resultInt / 100;//自己控制小數點

解決方案二:

使用BigDecimal,而且需要在構造參數使用String類型.

float和double只能用來做科學計算或者工程計算,在商業計算等精確計算中,要用java.math.BigDecimal。

在《EffectiveJava》這本書中就給出了一個解決方法。該書中也指出,float和double只能用來做科學計算或者是工程計算,在商業計算等精確計算中,我們要用java.math.BigDecimal。

BigDecimal類一個有4個方法,我們只關心對我們解決浮點型數據進行精確計算有用的方法,即

BigDecimal(double value) // 將double型數據轉換成BigDecimal型數據

原理:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM