浮點型數據(float, double)存儲IEEE標准解析和應用


  在C語言中,浮點型變量(也就是帶小數位的實數)在內存中的存儲方式遵循IEEE標准。

     首先來看單精度浮點型float。float占用4字節空間,也就是32位。從左向右數,第1位是符號位(0代表正數,1代表負數),接着是8位指數位,剩下的23位是數據位。如下所示

S EEEEEEEE DDDDDDDDDDDDDDDDDDDDDDD

    由於采用了科學計數法,所有的23位D位(數據位)全部用來記錄小數點右邊的數據,因為小數點左邊只有1位且它肯定是1(二進制)。

    以3.5為例,它的二進制形式是 11.1,轉換為科學計數法是 1.11E1。可以知道 S位(符號位 )應填入正(0),E位(指數位)為應填入1,D位(數據位)應填入11。

    PS:選擇3.5的原因是它可以正好被精確地轉換成二進制數。大多數的小數是不能被精確地轉換的,這涉及到十進制小數轉換二進制的精度問題。如3.6會是11.100110011001100(1100...)這種無限循環, 轉換成IEEE標准的小尾則是 66 66 66 40。為了方便和精確,本文選擇了3.5和-10.625這兩個可以被精確轉換的數。

    需要注意的是,E位的編碼形式並非常用的補碼形式(正數是它本身,負數符號位變1數據取反加一),而是把E位的8位能代表的數據空間(0-255)左右分為兩半,以127為中點,代表0。如果指數為是1,則E位是128;如果指數位是2,則E位是129;如果指數位是-1,則E位是126,以此類推。

    回到3.5的例子,我們可以得到E位實際上應該是128,也就是10000000。D位從左向右開始填,沒有的則為0。 所以,3.5的浮點表達為

0 10000000 11000000000000000000000

  整理為4位一組,則是

0100 0000 0110 0000 0000 0000 0000 0000

4      0       6      0       0      0       0      0

  可以推測,以小尾方式存儲在內存中的3.5,它的形式應該是 0000 6040用如下的示例程序結合WinHex來驗證。

 

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     float f = 3.5;
 6     printf("%f\r\n", f);
 7     printf("%p\r\n", &f);
 8     
 9     //此處用WinHex查看內存中f的存儲是否和預想的一樣
10     
11     system("pause");
12     
13     //此處用WinHex修改f在內存中的數值,並驗證是否的到預期的新浮點數
14     printf("%f\r\n", f);
15     
16     system("pause");
17     
18     return 0;
19 }

 

  編譯運行之后,得到f的值和他在內存中的地址。

    打開WinHex,選擇“查看RAM”,找到此程序並查看primary memory

  通過“轉到偏移地址”功能,跳到f的內存處(003BFAF8)。

    發現f的內存形式果然是剛才推測出的0000 6040

    驗證完我們的推測之后,嘗試通過直接修改內存的方式,把f的值由3.5改為-10.625。

    10.625的二進制形式為1010.101,科學計數法形式為1.010101E11。通過上面的公式,我們可以知道E位應填入130,即10000010。所以-10.625的浮點型是表達為

1 10000010 01010100000000000000000

1100 0001 0010 1010 0000 0000 0000 0000

C      1       2      A      0       0      0      0

  對應的小尾表達形式為0000 2AC1。

    通過WinHex修改f的內存。

    在程序中按回車鍵,程序繼續運行,並輸出f的值,此時可見f的值已被修改為-10.625。

  和float類型一樣,double類型也可以表示小數形式的變量,區別是float占4字節,而double占8字節。在浮點數的編碼上,double類型的E位有11位,多了3位(中值變為1023);D位有52位。

    在原程序的基礎上修改,加入一個double變量d,把它用同樣的步驟由3.5變為-10.625。

 

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     double d = 3.5;
 6     printf("%f\r\n", d);
 7     printf("%p\r\n", &d);
 8     
 9     //此處用WinHex查看內存中f的存儲是否和預想的一樣
10     
11     system("pause");
12     
13     //此處用WinHex修改d在內存中的數值,並驗證是否的到預期的新浮點數
14     printf("%f\r\n", d);
15     
16     system("pause");
17     
18     return 0;
19 }

   

    3.5(二進制11.1)的double形式為

0100 0000 0000 1100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

40 0C 00 00 00 00 00 00

  小尾方式為 00 00 00 00 00 00 0C 40

    編譯程序后,利用WINHEX查看d的內存內容。

    果然是這個保存形式。

    同樣的,我們嘗試把d從3.5修改為-10.625(二進制-1010.101, -1.010101E11)。它的double表達形式為

1100 0000 0010 0101 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

C0 25 40 00 00 00 00 00

  小尾方式為00 00 00 00 00 40 25 C0。

    在WinHex中修改d的內存。

    按回車鍵繼續程序,發現修改成功。

 


免責聲明!

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



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