Java中 float、double使用注意問題


在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)


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

2. System.out.println(2.00-1.10);中的1.10不能被計算機精確存儲,以double類型數據1.10舉例計算機如何將浮點型數據轉換成二進制存儲,
這里重點講小數部分轉換成二進制:
1.10整數部分就是1,轉換成二進制1(這里整數轉二進制不再贅述)
小數部分:0.1
0.1*2=0.2取整數部分0,基數=0.2
0.2*2=0.4取整數部分0,基數=0.4
0.4*2=0.8取整數部分0,基數=0.8
0.8*2=1.6取整數部分1,基數=1.6-1=0.6
0.6*2=1.2取整數部分1,基數=1.2-1=0.2
0.2*2=0.4取整數部分0,基數=0.4
.
.
.
.
直至基數為0。1.1用二進制表示為:1.000110...xxxx....(后面表示省略)
0.1 = 0*2^(-1)+0*2^(-2)+0*2^(-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();


免責聲明!

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



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