C語言浮點型數(shù)據(jù)在內(nèi)存中的存儲方式!

直接來吧!
常見的整形有int,unsigned int,signed int等,但在內(nèi)存中存儲時,char類型也可以歸為整形家族。
因為char類型是以ASCII碼的形式存儲在內(nèi)存當(dāng)中的,而ASCII碼是整形。
整形數(shù)據(jù)在內(nèi)存中是以二進(jìn)制的補碼形式來存儲的,但詳細(xì)并不在該篇中,今天我們來說一下浮點型在內(nèi)存中的存儲方式。
在C語言中,形如float,double等數(shù)據(jù)類型為浮點型也叫實型,而整形和浮點型在內(nèi)存中的存儲方式是不一樣的。

首先,我們要知道,數(shù)據(jù)在內(nèi)存中是以二進(jìn)制的形式存儲的。
根據(jù)標(biāo)準(zhǔn)(IEEE 754)定義,任何一個二進(jìn)制浮點數(shù)X,可以表示為以下形式:
公式:(-1)^S * M * 2^E
其中(-1)^S表示符號位,當(dāng)S=0,X為正數(shù);當(dāng)S = 1,X為負(fù)數(shù)
M表示有效數(shù)字;M的取值范圍是大于等于1,小于2的數(shù);1 ≦ M < 2。
2^E表示指數(shù)位

標(biāo)準(zhǔn)規(guī)定:
32位(單精度浮點):最高的1位是符號位S,接著的8位是指數(shù)E,剩下的23位為有效數(shù)M。
64位(雙精度浮點):最高的1位是符號位S,接著的11位是指數(shù)E,剩下的52位為有效數(shù)M。

針對M和E,標(biāo)準(zhǔn)還有特別規(guī)定:
先來說有效數(shù)M:
前面說過,M∈[1,2),也就是說,M可以寫成1.xxx的形式,其中xxx表示小數(shù)部分。
這樣就造成了在計算機內(nèi)部保存M時,默認(rèn)這個數(shù)的第一位總會是1,既然是恒定的數(shù)字那為什么還要讓他存在著浪費內(nèi)存空間呢?
所以啊,M在計算機內(nèi)部保存時,會無視這第一位的1,將后面的xxx存入M中,而在取出時再加上這第一位的1,既不影響浮點數(shù)在內(nèi)存中的存儲,也不使得內(nèi)存空間出現(xiàn)浪費。
再來說指數(shù)E:
首先,E是一個無符號整形(unsigned int),這意味著,如果E為8位,它的取值范圍就是0~255;如果E為11位,它的取值范圍就是0~2047.
我們知道,科學(xué)計算法中的E是可以出現(xiàn)負(fù)數(shù)的,所以標(biāo)準(zhǔn)規(guī)定,存入內(nèi)存中E的真實值必須再加上一個中間數(shù)。8位的E,這個中間數(shù)為127;11位的E,這個中間數(shù)為1023。
比如,2^10,E=10,所以保存成32位浮點數(shù)時,必須寫成10+127=137,即10001001

eg①:浮點數(shù)5.0在內(nèi)存中的存儲方式?
已知5.0為正數(shù),S=0
5.0的二進(jìn)制為101.0,將101.0小數(shù)點左移,直至小數(shù)點左邊的數(shù),符合M的取值范圍,得到:M = 1.01
從101.0到1.010,小數(shù)點向左移了2位,所以E=2
已知未知數(shù),代入公式:(-1)^0 * 1.01 * 2^2
接下來就是將數(shù)據(jù)存入內(nèi)存:
32位:
S占用1字節(jié),S為0,將0存入內(nèi)存中;
M占用23字節(jié),M為1.01,按標(biāo)準(zhǔn)將1省去得01,存入內(nèi)存中的就是0100 0000 0000 0000 0000 000(不夠補0,直到湊夠23位)
E占用8字節(jié),E=2,127+2=129,129的二進(jìn)制為:1000 0001
存入內(nèi)存中的順序依次為:
S -> E ->? M
0 10000001 01000000000000000000000
在內(nèi)存中的存儲形式:0100 0000 1010 0000 0000 0000 0000 0000(4位二進(jìn)制位 = 1位16進(jìn)制位)
編譯器調(diào)試地址:0x 00 00 a0 40(小端字節(jié)序。關(guān)于大小端字節(jié)序,該篇并無講解)
64位:
S占用1字節(jié),S為0,將0存入內(nèi)存中;
M占用52字節(jié),M為1.01,按標(biāo)準(zhǔn)將1省去得01,存入內(nèi)存中的就是0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000;
E占用11字節(jié),E=2,1023+2=1025,1025的二進(jìn)制為:100 0000 0001。
存入內(nèi)存中的順序依次為:
S -> E ->? M
0 10000000001 0100000000000000000000000000000000000000000000000000
在內(nèi)存中的存儲形式:0100 0000 0001 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000(4位二進(jìn)制位 = 1位16進(jìn)制位)
編譯器調(diào)試地址:0x 00 00 00 00 00 00 14 40? (小端字節(jié)序。關(guān)于大小端字節(jié)序,該篇并無講解)

eg②:浮點數(shù)48.5在內(nèi)存中的存儲方式?
我們知道48的二進(jìn)制怎么計算,那0.5的二進(jìn)制呢?
不要急,一步一步來,首先48.5為正數(shù),S=0。
小數(shù)二進(jìn)制詳解:
解法:乘2取余法
先看0.5的二進(jìn)制:
0.5*2 = 1 余 0
0.5 的二進(jìn)制就是 0.1
0.5太簡單,看不出來什么,那么我們再來看0.6875的二進(jìn)制:
0.6875 * 2 = 1 余 0.375
0.375 * 2 = 0 余 0.75
0.75 * 2 = 1 余 0.5
0.5 * 2 = 1 余 0
將所求整數(shù)由上而下(從上到下)依次排列得到1011,由于我們求的是小數(shù)的二進(jìn)制,所以要在1011前加上‘ 0. ’,最后得到‘ 0.1011 ’。
知道了方法,掌握了方法,就會進(jìn)行更深入的研究,我們再來看:
說明:
(須知知識!求一個數(shù)的負(fù)數(shù)次方公式:a^-x=1/a^x)
二進(jìn)制的1011,通過1*2^0 + 1*2^1 + 0*2^2 + 1*2^3 = 1+2+0+8 = 11
二進(jìn)制的0.1011,通過
? 1*2^-1 + 0*2^-2 + 1*2^-3 + 1*2^-4
= 1*(1/2^1) + 0*(1/2^2) + 1*(1/2^3) + 1*(1/2^4)?
= 1/2 + 0 + 1/8 + 1/16?
= 0.5 + 0 + 0.125 + 0.0625?
= 0.6875
已知48的二進(jìn)制為110000 ,0.5的二進(jìn)制為0.1,所以48.5的二進(jìn)制就是110000.1
將小數(shù)點左移,直至符合M的取值范圍M∈[1,2),M = 1.100001,共左移5位,E = 5。
已知未知數(shù),代入公式:(-1)^0 * 1.100001 * 2^5
接下來就是將數(shù)據(jù)存入內(nèi)存:
32位:
S占用1字節(jié),S為0,將0存入內(nèi)存中;
M占用23字節(jié),M為1.100001,按標(biāo)準(zhǔn)將1省去得100001,存入內(nèi)存中的就是1000 0100 0000 0000 0000 000;
E占用8字節(jié),E=5,127+5=132,132的二進(jìn)制為:1000 0100。
存入內(nèi)存中的順序依次為:
S -> E ->? M
0 10000100 10000100000000000000000
在內(nèi)存中的存儲形式:0100 0010 0100 0010 0000 0000 0000 0000(4位二進(jìn)制位 = 1位16進(jìn)制位)
編譯器調(diào)試地址:0x 00 00 42 42(小端字節(jié)序)
64位:
S占用1字節(jié),S為0,將0存入內(nèi)存中;
M占用52字節(jié),M為1.100001,按標(biāo)準(zhǔn)將1省去得100001,存入內(nèi)存中的就是1000 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000;
E占用11字節(jié),E=2,1023+5=1028,1028的二進(jìn)制為:100 0000 0100。
存入內(nèi)存中的順序依次為:
S -> E ->? M
0 10000000100 1000010000000000000000000000000000000000000000000000
在內(nèi)存中的存儲形式:0100 0000 0100 1000 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000(4位二進(jìn)制位 = 1位16進(jìn)制位)
編譯器調(diào)試地址:0x 00 00 00 00 00 40 48 40(小端字節(jié)序)

eg③:浮點數(shù)0.5在內(nèi)存中的存儲方式?
0.5為正數(shù),二進(jìn)制為0.1,M∈[1,2),所以小數(shù)點要像右移一位,M=1,E=-1;
(-1)^0 * 1 * 2^-1
接下來就是將數(shù)據(jù)存入內(nèi)存:
32位:
S占用1字節(jié),S為0,將0存入內(nèi)存中;
M占用23字節(jié),M為1,按標(biāo)準(zhǔn)將1省去沒了,內(nèi)存中補零0000 0000 0000 0000 0000 000;
E占用8字節(jié),E=-1,127-1=126,126的二進(jìn)制為:0111 1110
存入內(nèi)存中的順序依次為:
S -> E ->? M
0 01111110 00000000000000000000000
在內(nèi)存中的存儲形式:0011 1111 0000 0000 0000 0000 0000 0000(4位二進(jìn)制位 = 1位16進(jìn)制位)
編譯器調(diào)試地址:0x 00 00 00 3f(小端字節(jié)序)
64位:
S占用1字節(jié),S為0,將0存入內(nèi)存中;
M占用52字節(jié),M為1,按標(biāo)準(zhǔn)將1省去沒了,存入內(nèi)存中的就是0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000;
E占用11字節(jié),E=2,1023-1=1022,1022的二進(jìn)制為:011 1111 1110。
存入內(nèi)存中的順序依次為:
S -> E ->? M
0 01111111110 0000000000000000000000000000000000000000000000000000
在內(nèi)存中的存儲形式:0011 1111 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000(4位二進(jìn)制位 = 1位16進(jìn)制位)
編譯器調(diào)試地址:0x 00 00 00 00 00 00 e0 3f(小端字節(jié)序)

說完存儲,我們再來看取出:
將二進(jìn)制數(shù)據(jù)以浮點型取出,需要將所做修改盡數(shù)還原,最主要的是E:
指數(shù)E從內(nèi)存中取出分成三種情況:
1.E不全為0或不全為1(該情況為正常情況。怎么來的,就怎么回去)
首先,E需要轉(zhuǎn)為十進(jìn)制并減去(32位:127 或 64位:1023),得到真實值,再將M的1補回,反推公式,得到浮點數(shù)。
(2,3較特殊且不常見,如果掌握上述知識,完全可根據(jù)自身條件進(jìn)行推導(dǎo))
2.E全為0(無窮?。?/p>
此時,浮點數(shù)的指數(shù)E=1-127或1-1023即為真實值,有效數(shù)字M不再補回第一位的1,而是還原為0.xxx的小數(shù)。
這樣做是為了表示±0,以及接近于0的很小的數(shù)字。
(0.0000000000000000000000000000001如果真的有一天需要你用手推這種數(shù),那么可能是你穿越了)
3.E全為1(無窮大)
此時,如果有效數(shù)字M全為0,表示±∞(正負(fù)取決于符號位S)

eg④:32位:0100 0000 1010 0000 0000 0000 0000 0000以浮點數(shù)取出賦給a,a=_?
用已知知識反推,將二進(jìn)制串分割成易讀的:0 10000001 01000000000000000000000
M補1 = 1.01000000000000000000000 = 1.01
E = 1000 0001 = 129 -> 129-127 = 2
反推公式:(-1)^S * M * 2^E = (-1)^0 * 1.01 * 2^2(可有可無)
答:M = 1.01 -> 右移2位得 101.0 轉(zhuǎn)回十進(jìn)制 5.0
感謝大家能看到這里!