Java中double和float的比較及使用

在java中運行一下代碼

System.out.println(2.00-1.10);
輸出的結果是:0.8999999999999999
很奇怪,並不是我們想要的值0.9

再運行如下代碼:
System.out.println(2.00f-1.10f);
輸出結果:0.9

又正確了,爲什麼會導致這種問題?程序中爲什麼要儘量避免浮點數比較?

在java中浮點型默認是double的,及2.00和1.10都要在計算機裏轉換進行二進制存儲,這就涉及到數據精度,出現這個現象的原因正是浮點型數據的精度問題。先了解下float、double的基本知識:

  1. float和double是java的基本類型,用於浮點數表示,在java中float佔4個字節32位,double佔8個字節64位,一般比較適合用於工程測量計算中,其在內存裏的存儲結構如下:

float:

符號位(1 bit)
指數(8 bit)
尾數(23 bit)
double:

符號位(1 bit)
指數(11 bit)
尾數(52 bit)

注意:從左到右是從低位到高位,而在計算機內部是採用逆序存儲的。

  1. System.out.println(2.00-1.10);中的1.10不能被計算機精確存儲,以double類型數據1.10舉例計算機如何將浮點型數據轉換成二進制存儲,
    這裏重點講小數部分轉換成二進制:
    1.10整數部分就是1,轉換成二進制1(這裏整數轉二進制不再贅述)
    小數部分:0.1
    0.12=0.2取整數部分0,基數=0.2
    0.2
    2=0.4取整數部分0,基數=0.4
    0.42=0.8取整數部分0,基數=0.8
    0.8
    2=1.6取整數部分1,基數=1.6-1=0.6
    0.62=1.2取整數部分1,基數=1.2-1=0.2
    0.2
    2=0.4取整數部分0,基數=0.4
    .
    .
    .
    .
    直至基數爲0。1.1用二進制表示爲:1.000110…xxxx…(後面表示省略)
    0.1 = 02(-1)+0*2(-2)+02(-3)+1*2(-4)+…而double類型表示小數部分只有52位,當向後計算 52位後基數還不爲0,那後面的部分只能捨棄,從這裏可以看出float、double並不能準確表示每一位小數,對於有的小數只能無限趨向它。在計算機 中加減成除運算實際上最後都要在計算機中轉換成二進制的加運算,由此,當計算機運行System.out.println(2.00-1.10);
    時會拿他們在計算機內存中的二進制表示計算,而1.10的二進制表示本身就不準確,所以會出現0.8999999999999999的結果。

但爲什麼System.out.println(2.00f-1.10f);得出的結果是0.9呢。因爲float精度沒有double精度那麼大,小數部分0.1二進制表示被捨去的比較多。

注意:

程序中應儘量避免浮點數的比較
float、double類型的運算往往都不準確
解決方法:

使用BigDecimal提供的方法進行比較或運算,但要注意在構造BigDecimal的時候使用float、double的字符串形式構建,BigDecimal(String val);爲什麼不用BigDecimal(double val)API裏寫的比較清楚。

運算以減法爲例:

BigDecimal b1 = new BigDecimal(Double.toString(2.00));

BigDecimal b2 = new BigDecimal(Double.toString(1.10));

double result = b1.subtract(b2).doubleValue();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章