由于對float或double 的使用不當,可能會出現精度丢失的問題。問題大概情況可以通過如下代碼了解:
public class floatdoubletest {
public static void main(string[] args) {
float f = 20014999;
double d = f;
double d2 = 20014999;
system.out.println("f=" + f);
system.out.println("d=" + d);
system.out.println("d2=" + d2);
}
得到的結果如下:
f=2.0015e7
d=2.0015e7
d2=2.0014999e7
從輸出結果可以看出double 可以正确的表示20014999 ,而float 沒有辦法表示20014999 ,得到的隻是一個近似值。這樣的結果很讓人訝異。20014999 這麼小的數字在float下沒辦法表示。于是帶着這個問 題,做了一次關于float和double學習,做個簡單分享,希望有助于大家對java 浮 點數的了解。
關于 java 的 float 和 double
java 語言支援兩種基本的浮點類型: float 和 double 。java 的浮點類型都依據 ieee 754 标準。ieee 754 定義了32 位和 64 位雙精度兩種浮點二進制小數标準。
ieee 754 用科學記數法以底數為 2 的小數來表示浮點數。32 位浮點數用 1 位表示數字的符号,用 8 位來表示指數,用 23 位來表示尾數,即小數部分。作為有符号整數的指數可以有正負之分。小數部分用二進制(底數 2 )小數來表示。對于64 位雙精度浮點數,用 1 位表示數字的符号,用 11 位表示指數,52 位表示尾數。如下兩個圖來表示:
float(32位):

double(64位):
都是分為三個部分:
(1) 一 個單獨的符号位s 直接編碼符号s 。
(2)k 位 的幂指數e ,移 碼表示 。
(3)n 位 的小數,原碼表示 。
那麼 20014999 為什麼用 float 沒有辦法正确表示?
結合float和double的表示方法,通過分析 20014999 的二進制表示就可以知道答案了。
以下程式可以得出 20014999 在 double 和 float 下的二進制表示方式。
public class floatdoubletest3 {
double d = 8;
long l = double.doubletolongbits(d);
system.out.println(long.tobinarystring(l));
float f = 8;
int i = float.floattointbits(f);
system.out.println(integer.tobinarystring(i));
輸出結果如下:
double:100000101110011000101100111100101110000000000000000000000000000
float:1001011100110001011001111001100
對于輸出結果分析如下。對于都不 double 的二進制左邊補上符号位 0 剛好可以得到 64 位的二進制數。根據double的表 示法,分為符号數、幂指數和尾數三個部分如下:
0 10000010111 0011000101100111100101110000000000000000000000000000
對于 float 左邊補上符 号位 0 剛好可以得到 32 位的二進制數。 根據float的表示法, 也分為 符号數、幂指數和尾數三個部分如下 :
0 10010111 00110001011001111001100
綠色部分是符号位,紅色部分是幂指數,藍色部分是尾數。
對比可以得出:符号位都是 0 ,幂指數為移碼表示,兩者剛好也相等。唯一不同的是尾數。
在 double 的尾數 為: 001100010110011110010111 0000000000000000000000000000 ,省略後面的零,至少需要24位才能正确表示。
而在 float 下面尾數 為: 00110001011001111001100 ,共 23 位。
為什麼會這樣?原因很明顯,因為 float尾數 最多隻能表示 23 位,是以 24 位的 001100010110011110010111 在 float 下面經過四舍五入變成了 23 位的 00110001011001111001100 。是以 20014999 在 float 下面變成了 20015000 。
也就是說 20014999 雖然是在float的表示範圍之内,但 在 ieee 754 的 float 表示法精度長度沒有辦法表示出 20014999 ,而隻能通過四舍五入得到一個近似值。
總結:
浮點運算很少是精确的,隻要是超過精度能表示的範圍就會産生誤差。往往産生誤差不是 因為數的大小,而是因為數的精度。是以,産生的結果接近但不等于想要的結果。尤其在使用 float 和 double 作精确運 算的時候要特别小心。
可以考慮采用一些替代方案來實作。如通過 string 結合 bigdecimal 或 者通過使用 long 類型來轉換。
特别說明:尊重作者的勞動成果,轉載請注明出處哦~~~http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt357