浮點型數據存儲方式分析(轉)
分類: C/C++
點擊(此處)折疊或打開
- const float ESPSION = 0.000001;
- if((x-y)>=-ESPSION && (x-y)<= ESPSION)
點擊(此處)折疊或打開
- typedef union test
- {
- float a;
- int i;
- char c[4];
- }Test;
- int main()
- {
- Test t;
- t.a = 5.0;
- printf("%f\n",t.a)
- printf("%d\n",t.i);
- printf("%c,%c,%c,%c\n",t.c[3],t.c[2],t.c[1],t.c[0]);
- return 0;
- }
浮點型變量在計算機內存中占用4字節(Byte),即32-bit。遵循IEEE-754格式標準。一個浮點數由2部分組成:底數m 和 指數e。
±mantissa × 2^exponent
(注意,公式中的mantissa 和 exponent使用二進制表示)
(具體可參看深入理解計算機系統)
底數部分 使用2進制數來表示此浮點數的實際值。
指數部分 占用8-bit的二進制數,可表示數值范圍為0-255。但是指數應可正可負,所以IEEE規定,此處算出的次方(即是來自內存存儲的內容,存儲指數)須減去127才是真正的指數(實際的指數,如12.5轉換為二進制為:1100.100=1.100100*23, 3即為實際指數)。所以float的指數可從 -126到128.
底數部分實際是占用24-bit的一個值,由于其最高位始終為1,所以最高位省去不存儲,在存儲中只有23-bit。到目前為止,底數部分23位加上指數部分8位 使用31位。那么前面說過,float是占用4個字節即32-bit, 那么還有一位是干嘛用的呢? 還有一位,其實就是4字節中的最高位,用來指示浮點數的正負,當最高位是1時,為負數,最高位是0時,為正數。
也就是說我們可以認為float在小端CPU的編碼方式應該是:
31<-------------------------------------------------0
S(1bit)| E(8bits)| M(23bits) |
即:
-----------------------------------------------------
ADDR0+3 ADDR0+2 ADDR0+1 ADDR0
SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
-----------------------------------------------------
S: 表示浮點數正負,1為負數,0為正數。
E: 指數加上127后的值的二進制數
M: 24-bit的底數(只存儲23-bit)
需要注意,浮點數為0時,指數和底數都為0,但此前的公式不成立。因為2的0次方為1,所以,0是個特例。當然,這個特例也不用認為去干擾,編譯器會自動去識別。
這樣我們就可以知道前面這個題中輸出的結果啦,從上面的分析可以知道一個float型的數的基本存儲方式,按照上面的實現可以知道5.0的存儲方式為如下的形式:
01000000101000000000000000000000
從上面的這個存儲形式我們可以得到基本的整形數值時0x40A00000。進而也就知道了4個bytes中的數值大小。
這是充分利用了聯合體的共享內存特性,我們改變程序如下所示:
點擊(此處)折疊或打開
- #include<stdio.h>
- typedef union test
- {
- float a;
- int i;
- char c[4];
- }Test;
- int main()
- {
- Test t;
- t.a = 5.0;
- printf("%f\n",t.a);
- printf("%d\n",t.i);
- printf("%c,%c,%c,%c\n",t.c[3],t.c[2],t.c[1],t.c[0]);
- t.i = 65;
- printf("%f\n",t.a);
- printf("%d\n",t.i);
- printf("%c,%c,%c,%c\n",t.c[3],t.c[2],t.c[1],t.c[0]);
- return 0;
- }
根據上面的分析,可以比較方便的計算出結果如下所示:
當然這只是我在X86系統中的輸出,在大端系統中會是什么結果我不得而知,具體的要參看IEEE標準。
float類型的數據是比較復雜的問題,我將在后面認真研究,爭取早日解決各種問題。