1、在電氣和電子工程師協會IEEE 754 標准中
-
float單精度浮點數(4個字節,32位)在機器中表示:用1位表示數字的符號(正負號),8位表示指數,23位表示尾數(即小數部分)
-
double雙精度浮點數(8個字節,64位):1位表示符號(正負號),11位表示指數,52位表示尾數
浮點數階碼E用“指數e的移碼-1”表示,還可以用階碼E的移碼(特殊的移碼)+階碼E的真值(即指數)表示。
階碼的移碼:假設階碼用8個二進制位表示,則該階碼的移碼為 2(n-1) ,但注意這里的移碼是特殊的移碼,僅偏移2(n-1)-1=127 。
2、浮點數的規格化
同一浮點數表示方式不唯一(如1.5=1.01x2(0) =0.101*2(1)),所以規定當尾數不為0時,向左或向右移動小數點,使得小數點左邊始終為1(即1.M的格式)。
3、單精度浮點數真值
一個規格化32位的浮點數x的真值表示為:x=(-1)(s)x(1.M)x2(e) , e=E-127 , E=e的移碼-1
4、十進制到機器碼
(1)0.5=(0.1)(二進制),符號位s為0,指數為e=-1,規格化后尾數為1.0
單精度浮點數尾數域(從小數點后開始)共23位,右側以0補全,尾數域:
M=[000 0000 0000 0000 0000 0000](二進制)
階碼E:E=[-1](的移碼)-1=[0111 1111](二進制)-1=[0111 1110](二進制)
或者 E=127(2(8-1)-1,特殊的移碼)+(-1)(指數)=126=[0111 1110](二進制)
將符號位s,階碼E和尾數域M存放到指定位置,可得0.5的機器碼為:
0.5=[0011 1111 0000 0000 0000 0000 0000 0000](二進制)
十六進制表示為:0.5=0x3f000000 (0x:表示十六進制,0011:3,1111:f,)
(2)1.5=[1.1](二進制),符號位為0,指數e=0,規格化后尾數為1.1。
尾數域M右側以0補全:M=[100 0000 0000 0000 0000 0000](二進制)
階碼E:E=[0](的移碼)-1=[10000000](二進制)-1=[01111111](二進制)
得1.5的機器碼:1.5=[0011 1111 1100 0000 0000 0000 0000 0000](二進制)
十六進制表示:1.5=0x3fc00000
(3)−12.5=[−1100.1](二進制) ,符號位S為1,指數e為3,規格化后尾數為1.1001,
尾數域M右側以0補全:
M=[100 1000 0000 0000 0000 0000] (二進制)
階碼E:
E=[3](的移碼)−1=[1000 0011](二進制)−1=[1000 0010](二進制)
即-12.5的機器碼:
−12.5=[1100 0001 0100 1000 0000 0000 0000 0000](二進制)
十六進制表示:-12.5=0xc1480000 。
5、機器碼到十進制
若某個浮點數的IEEE 754標准存儲格式為0x41360000,那么其浮點數的十進制數值為多少:
0x41360000=[0 10000010 011 0110 0000 0000 0000 0000]
有上述機器碼可知符號位s=0,指數e=階碼-127=1000 0010-127=130-127=3,或者階碼+1=移碼,移碼變換為原碼求得指數 ,10000010+1=10000011(移碼)=00000011(原碼)=3(指數e)
尾數域為:011 0110 0000 0000 0000 0000,第一個0的左邊隱藏了一個1,即尾數1.M=1.011 0110 0000 0000 0000 0000
於是:x=(-1)(s)x1.Mx2(e)=+(1.011011)x2(3)=+1011.011=(11.375)(十進制)
6、浮點數的特殊情況
(1)0的表示(32位為例)
如果階碼E=0,且尾數M是0,則這個數的真值為+0或-0
+0機器碼為:0 00000000 000 0000 0000 0000 0000 0000
-0機器碼為:1 00000000 000 0000 0000 0000 0000 0000
浮點數不能精確表示0,而是以很小的數來近似表示0,以32位單精度浮點數為例:
x=(-1)(s)x(1.M)x2(e) , e=E-127
+0的機器碼對應的真值為:1.0x2^(-127)
-0的機器碼對應的真值為: -1.0x2^(-127)
(2) ±∞的表示(32位為例)
如果階碼E=255,且尾數M是0,則這個數的真值為+∞或-∞
+∞的機器碼為:0 11111111 000 0000 0000 0000 0000 0000
-∞的機器嗎為:1 11111111 000 0000 0000 0000 0000 0000
x=(-1)(s)x(1.M)x2(e) , e=E-127
+∞的機器碼對應真值為:1.0x2^(128)
-∞的機器碼對應真值為:-1.0x2^(128)
7、浮點數的精度
浮點數的精度是由尾數的位數來決定的:
- 對於
float
型浮點數,尾數部分23
位,換算成十進制就是2^23=8388608
,所以十進制精度只有6 ~ 7
位; - 對於
double
型浮點數,尾數部分52
位,換算成十進制就是2^52 = 4503599627370496
,所以十進制精度只有15 ~ 16
位
例題:以下例題是在java編譯環境下檢測的。
1、為什么以下返的結果為true
?
System.out.println(1f==0.99999999f);
//結果返回 true
分析:
1.0(十進制)=1.0(二進制)* 20
↓
0 01111111 0000000 00000000 00000000(二進制)
↓
0x3F800000(十六進制)
0.99999999(十進制)
=0.111 111 111 111 111 111 111 111110(二進制)
(猜測:浮點數的尾數只有23位,事先將第24位加一,把進位加到第23位,結果為1.0000000 00000000 00000000)
(實際上和編譯器有關,當小數點后的23位全為0時,編譯器就當成全0處理,即0.0000000 00000000 00000000)
=0.0000000 00000000 00000000* 20
↓
0 01111111 0000000 00000000 00000000(二進制)
↓
0x3F800000(十六進制)
原因:float
型浮點數十進制精度只有6 ~ 7
位,而0.99999999f
小數點后有8位,超出了精度范圍(猜測產生了進位)。
2、為什么以下返回的結果為`false`?
System.out.println(1f==0.9999999f);
//結果返回 false
分析:
0.9999999(十進制)
=0.1111111 11111111 111111110(二進制)
(第24位為0加一不產生進位,所以結果是小數點后23個1,最后進行規范化處理缺位補0)
=1.111111 11111111 11111110(二進制) * 2-1
↓
0 01111110 1111111 11111111 11111110(二進制)
↓
0x3F7FFFFE(十六進制)
這些只是我個人的理解,可能不是很精確,如有錯誤歡迎指正,相互交流共同進步!