目錄
前言
一、引例
二、浮點型在內存中的存儲
三、浮點數在內存中的存和取過程
1.浮點數的存儲過程
2.浮點數的取過程
四、引例解析
總結
前言
? ? ? ? 想知道浮點數在內存中是如何存儲的嗎,本文就告訴你答案,雖然一般情況題目還是面試涉及到浮點數在內存中的存儲很少,但是了解其存儲機制有利于加深我們對C語言的理解,修煉我們的內功。
??感謝支持,點贊關注不迷路??
?
?
一、引例
我們看以下代碼:
#include <stdio.h>int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值為:%d\n", n);printf("pFloat的值為:%f\n", *pFloat);*pFloat = 9.0;printf("n的值為:%d\n", n);printf("pFloat的值為:%f\n", *pFloat);return 0;
}
運行結果:
發現:我們觀察到,將整數9以浮點型打印時為0.000000,將浮點型9.0以整形打印時是一個較大的數字。這一點就可以說明整形與浮點型在內存中的存儲形式是不同的。
二、浮點型在內存中的存儲
我們知道整數在內存中是以補碼的形式儲存的,那么浮點數是怎么存儲的呢?
根據國際標準IEEE(電氣和電子工程協會)754,任意一個?進制浮點數V可以表示成下面的形式:
舉例:浮點數5.5用以上形式如何表示:
- 首先5.5翻譯成二進制為 101.1。
- 然后就可以改寫成以下形式:
- 這時候,M就是1.011,E就是2,S自然為0
然后,只需要將S、M、E這三個數存儲到內存中,就可以儲存一個浮點數了,那么這三個數是如何在內存中存放的呢?
IEEE 754規定:
- 對于32位的浮點數(float),最?的1位存儲符號位S,接著的8位存儲指數E,剩下的23位存儲有效數
- 字M 對于64位的浮點數(double),最?的1位存儲符號位S,接著的11位存儲指數E,剩下的52位存儲有效數字M
注意:不管怎樣,內存中存儲的還是補碼
??
三、浮點數在內存中的存和取過程
1.浮點數的存儲過程
IEEE 754對有效數字M和指數E,還有一些特別規定。
M的存儲過程:前面用101.1舉例,可以寫成類似科學計數法的形式。1<=M<2,也就是說,M可以寫成 1.xxxxxx 的形式,其中 xxxxxx 表表示小數部分。那么就有以下規定:
IEEE 754規定,在計算機內部保存M時,默認這個數的第?位總是1,因此可以被舍去,只保存后面的 xxxxxx部分。比如保存1.01的時候,只保存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節省1位有效數字。以32位浮點數為例,留給M只有23位,將第?位的1舍去以后,等于可以保存24位有效數字。
E的存儲過程:指數E,情況就比較復雜首先,E為一個無符號整數(unsigned int),這意味著,如果E為8位,它的取值范圍為0~255;如果E為11位,它的取值范圍為0~2047。但是,我們知道,科學計數法中的E是可以出現負數的。E又是無符號整數,所以規定:
IEEE754規定,存入內存時E的真實值必須再加上一個中間數,對于8位的E,這個中間數是127;對于11位的E,這個中間數是1023。比如,2^10的E是 10,所以保存成32位浮點數時,必須保存成10+127=137,即10001001。
舉例:浮點數(float)5.5,二進制位:101,1
- S:0,E:2,M:001
- 但是E存入內存時(float)要加上127等于129
- 結果就是 0 10000001 01100000000000000000000
- 注意:M后不夠是補0的
- 0100 0000 1011 0000 0000 0000 0000 0000翻譯為16進制為0x40 b0 00 00
- 然后我們在VS中調試觀察,驗證以下
- 因為VS是小端存儲,所以是倒著存,結果一致
2.浮點數的取過程
這里主要是指數E從內存中取出還可以再分成三種情況:
1.E不全為0或不全為1(和上面舉例一樣,正常取)
這時,浮點數就采用下面的規則表示,即指數E的計算值減去127(或1023),得到真實值,再將有效數字M前加上第一位的1。
比如:0.5的二進制形式為0.1,由于規定正數部分必須為1,即將小數點右移1位,則為1.0*2^(-1),其階碼為-1+127(中間值)=126,表示為01111110,而尾數1.0去掉整數部分為0,補齊0到23位 00000000000000000000000,則其二進制表示形式為:
0 01111110 00000000000000000000
2.E全為0(特殊情況)
這時,浮點數的指數 E?等于1-127(或者1-1023)即為真實值,有效數字M不再加上第一位的1,而是還原為0.xxxxxx的小數。這樣做是為了表示±0,以及接近于0的很小的數字。
比如1.0*2的負127次方,這個數無限接近于0,所以M讀取時不再加上1,并且指數讀取時是減126而不是127,因為M的整數位1被移到了小數部位,所以內存中為0 00000000 00000000000000000000000,讀取時就是0.000000
3.E全為1(特殊情況)
這時,浮點數指數 E 等于128,如果有效數字M全為0,表示±無窮大(正負取決于符號位s);
我們可以簡單算一下,2的32次方大約42億,那么4個42移相乘,那數字將會非常大。
四、引例解析
引例中的結果:
我們來一步一步分析:
- 首先 int n = 9,它在內存中的補碼為:00000000 00000000 00000000 00001001。以%d打印肯定是9沒毛病。
- 然后通過指針把它當做浮點型打印,這時編譯器就會將n的補碼以浮點數的格式進行讀取,float為32個比特位,可以寫成0 00000000 00000000000000000001001。
- 這里 E 的部分全為0,對應了上文第二種情況,E將無限接近于0,讀取出來就是,0.9*2的負126次方,等于0.00000...9,而編譯器默認打印小數點后6位,因此結果才為0.000000
- 通過指針將n的空間存的值修改為9.0,而9.0將會以32位浮點型的格式存儲到內存中,9.0翻譯為二進制為:1001.0,變為科學計數法為:1.001*2^3,那么S:0,E:3,M:1.001
- E存入內存要加上127等于130,二進制為:10000010,因此9.0存入內存的二進制為:0 10000010 00100000000000000000000
- 將?01000001000100000000000000000000以整形的格式讀取時就為:
- 以浮點型%f讀取就是正常9.0
所以我們在拿到一個數據時,非特殊一定要以正確的格式讀取,否則就不是你想要的數字
總結
? ? ? ? 以上就是本文的全部內容,希望對你有所幫助。