這是浮點數的通常表示形式,在IEEE754中,單精度浮點數有如下形式:
32位單精度
單精度二進制小數,使用32個比特存儲。
1 |
8 |
23位長 |
S |
Exp |
Fraction |
31 |
30至23 |
22至0位編號(從右邊開始為0) |
S為符號位,Exp為指數字,Fraction為有效數字。 指數部分即使用所謂的偏正值形式表示,偏正值為實際的指數大小與一個固定值(32位的情況是127)的和。采用這種方式表示的目的是簡化比較。因為,指數的值可能為正也可能為負,如果采用補碼表示的話,全體符號位S和Exp自身的符號位將導致不能簡單的進行大小比較。正因為如此,指數部分通常采用一個無符號的正數值存儲。單精度的指數部分是−126~+127加上偏移值127,指數值的大小從1~254(0和255是特殊值)。浮點小數計算時,指數值減去偏正值將是實際的指數大小。(當指數為0的時候,用非規約數表示,這樣做的理由在於,所有的非歸約數都比歸約數更加接近0,非規約形式的浮點數的指數值是同種情況下規約形式浮點數的指數值再加1。)
注意通常情況下,23位尾數部分前邊自動省略了一個整數部分1,也就是說 num = -1^S * 2^(Exp+127) * (1.xxxxxxx……) 其中xxxx表示尾數部分。
此外有一些特別的約定:
單精度浮點數各種極值情況:
類別 |
正負號 |
實際指數 |
有偏移指數 |
指數域 |
尾數域 |
數值 |
零 |
0 |
-127 |
0 |
0000 0000 |
000 0000 0000 0000 0000 0000 |
0.0 |
負零 |
1 |
-127 |
0 |
0000 0000 |
000 0000 0000 0000 0000 0000 |
−0.0 |
1 |
0 |
0 |
127 |
0111 1111 |
000 0000 0000 0000 0000 0000 |
1.0 |
-1 |
1 |
0 |
127 |
0111 1111 |
000 0000 0000 0000 0000 0000 |
−1.0 |
最小的非規約數 |
* |
-126 |
0 |
0000 0000 |
000 0000 0000 0000 0000 0001 |
±2−23 × 2−126 = ±2−149 ≈ ±1.4×10-45 |
中間大小的非規約數 |
* |
-126 |
0 |
0000 0000 |
100 0000 0000 0000 0000 0000 |
±2−1 × 2−126 = ±2−127 ≈ ±5.88×10-39 |
最大的非規約數 |
* |
-126 |
0 |
0000 0000 |
111 1111 1111 1111 1111 1111 |
±(1−2−23) × 2−126 ≈ ±1.18×10-38 |
最小的規約數 |
* |
-126 |
1 |
0000 0001 |
000 0000 0000 0000 0000 0000 |
±2−126 ≈ ±1.18×10-38 |
最大的規約數 |
* |
127 |
254 |
1111 1110 |
111 1111 1111 1111 1111 1111 |
±(2−2−23) × 2127 ≈ ±3.4×1038 |
正無窮 |
0 |
128 |
255 |
1111 1111 |
000 0000 0000 0000 0000 0000 |
+∞ |
負無窮 |
1 |
128 |
255 |
1111 1111 |
000 0000 0000 0000 0000 0000 |
−∞ |
* |
128 |
255 |
1111 1111 |
non zero |
NaN |
|
* 符號位可以為0或1 . |
這里邊比較值得一提的,一個是NaN的設置,還有一個是指數為0情況下幾種數字的關系。
1. 在NaN中,尾數必須要非零。
2. 中間大小的非歸約數的二倍正好是最小的歸約數,同時也是最大的非規約數;因此,在對浮點數進行乘二操作時,可以依照如下代碼:
-
unsigned float_twice(unsigned uf) {
-
unsigned expn = (uf >> 23) & 0xFF;
-
unsigned sign = uf & 0x80000000;
-
unsigned frac = uf & 0x007FFFFF;
-
if (expn == 255 || (expn == 0 && frac == 0)) return uf;
-
if (expn) {
-
expn++;
-
} else
-
frac <<= 1;
-
return (sign) | (expn << 23) | (frac);
-
}
首先檢測是否為-0;然后看如果不是特殊數字的話,就將指數自增;如果是特殊數字(需要考慮的特殊數字只有指數是0的情況下需要單獨進行考慮),對於最大的非規約數,則要增加指數並改變自身(因為此時由非歸約數轉化為了歸約數),對於其他情形,則只需要左移一位,如果發生了進位,則此時正好變為規約表示,前面省略了一個1;如果沒發生進位,則代表尾數部分放大二倍,而整個數字就只有尾數部分。
在需要進行舍尾操作時,采取四舍六入五六雙的Bankers' Round規則。