1. 程式人生 > >十進位制浮點數的二進位制轉換及儲存

十進位制浮點數的二進位制轉換及儲存

網上看到一道小題:

int main(void) 
{
float a = 10.0;

double b = 10.0;

printf( "%d\n", a );

printf( "%d\n", b );

return 0;

}

輸出結果a,b均為0。

這道小題是一個很好的面試題,考查面試者對浮點數儲存的理解。

十進位制小數的二進位制表示:

整數部分:除以2,取出餘數,商繼續除以2,直到得到0為止,將取出的餘數逆序

小數部分:乘以2,然後取出整數部分,將剩下的小數部分繼續乘以2,然後再取整數部分,一直取到小數部分為零為止。如果永遠不為零,則按要求保留足夠位數的小數,最後一位做0舍1入。將取出的整數順序排列。

舉例:22.8125 轉二進位制的計算過程:

整數部分:除以2,商繼續除以2,得到0為止,將餘數逆序排列。
22 / 2  11 餘0
11/2     5  餘 1
5  /2      2  餘 1
2  /2      1  餘 0
1  /2      0  餘 1
得到22的二進位制是10110


小數部分:乘以2,取整,小數部分繼續乘以2,取整,得到小數部分0為止,將整數順序排列。
0.8125x2=1.625取整1,小數部分是0.625
0.625x2=1.25取整1,小數部分是0.25
0.25x2=0.5取整0,小數部分是0.5
0.5x2=1.0取整1,小數部分是0,

得到0.8125的二進位制是0.1101

結果:十進位制22.8125等於二進位制00010110.1101

浮點數的計算機儲存:

IEEE 754標準中所定義的單精度32位浮點數和雙精度64位浮點數的格式:

32位單精度

單精度二進位制小數,使用32位儲存。 1 8 23 位長 +-+--------+-----------------------+ |S| Exp | Fraction | +-+--------+-----------------------+ 31 30 23 22 0 位編號 (從右邊開始為0) 偏正值 +127

64位雙精度

雙精度二進位制小數,使用64位儲存。 1 11 52 位長 +-+--------+-----------------------+ |S| Exp | Fraction | +-+--------+-----------------------+ 63 62 52 51 0 位編號 (從右邊開始為0) 偏正值 +1023

單精度的E為指數值+127,雙精度的E為指數值+1023,IEEE標準要求浮點數必須是規範的,也就是說尾數的小數點左側必須為1,因此在儲存尾數時可以省略小數點左側的1,這樣實際上對於float型別我們是用了23bits表示了24bits尾數。

以32位單精度浮點數為例:

十進位制22.8125轉換為二進位制表示為00010110.1101,

00010110.1101 = 1.01101101 * 2^4

由此得出 符號位S為0,表示正數

指數位E為4+127=131D=10000011B

尾數F為1.01101101去掉小數點左側的1,即為01101101

這樣十進位制22.8125轉換為二進位制表示為00010110.1101,計算機儲存為01000001101101101000000000000000

01000001101101101000000000000000

1bit8bits23bits
 S
 E  F
符號位
指數位尾數位

回頭再看最開始的小題,就容易多了。

10.0的二進位制表示為1010.0= 1.010*2^3

float型別的10.0:

符號位S為0

指數E為3+127=130=10000010

尾數F為010

double型別的10.0:

符號位S為0

指數E為3+1023=1026=10000000010

尾數F為010


最終結果:

float型別的10.0轉換為二進位制為1010.0儲存形式為01000001001000000000000000000000,16進製表示為0x41200000

double型別的10.0轉換為二進位制為1010.0儲存形式為0100000000100100後面用0補全,16進製表示為0x40240000

程式碼驗證一下:

int main(void) 
{
    float a = 10.0;
    double b = 10.0;
    int * pa = (int *)&a;
    int * pb = (int *)&b;


    printf( "%d\n", a );
    printf( "%x\n", *pa );
    printf( "%x\n", *(pb+1) );
    
return 0;
}

輸出結果:

$ ./a.out
0
41200000
40240000

IEEE 754 單精度浮點數轉換,線上計算http://www.styb.cn/cms/ieee_754.php