浮點型在內存中的存在方式

介紹

c=[100.0,-100.0,-0.5,10.25]  ;idl代碼,表示float型的array
allen@xps:~$ od -x sample
0000000 0000 42c8 0000 c2c8 0000 bf00 0000 4124
0000020

也就是說float數組在內存中是這個樣子

0000 42c8 0000 c2c8 0000 bf00 0000 4124

100 ->0000 42c8
-100->0000 c2c8
注意我們應該把上面的16進制數倒過來看,也就是
42c8 0000=0100 0010 1100 1000 0000 0000 0000 0000=0 10000101 10010000000000000000000=+(1.1001)2×2128+4+1127=(1100100)2=100
c2c8 0000=1100 0010 1100 1000 0000 0000 0000 0000=1 10000101 10010000000000000000000=(1.1001)2×2128+4+1127=(1100100)2=100
可見只有符號位改變了
所以,原碼/反碼/補碼的概念只適用於整形!

但是上面怎麼倒過來了,,內存中本來就是這樣的嗎?

還有,用hexedit打開的話,是這個樣子:

00 00 C8 42 00 00 C8 C2 00 00 00 BF 00 00 24 41

什麼鬼?

再試了一下用Sublime TextEdit 3打開,也是和hexedit打開一樣(這應該是內存中真正的樣子)

0000 c842 0000 c8c2 0000 00bf 0000 2441

但如果按照
IEEE 754
這種讀法的話,應該這樣看

42c8 0000 c2c8 0000 bf00 0000 4124 0000

當一個文件中包含了int型

#include <stdio.h>
int main()
{
    unsigned int a[]={0,1,2,3};
    int b[]={0,1,2,3};
    int c[]={0,-1,-2,-3};
    int d[]={131072,262144,524288,524288*2};  //2^17, 2^18 and so on
    FILE *file;
    file=fopen("/home/allen/sample_int","w");
    fwrite(a,sizeof(unsigned int),4,file);
    fwrite(b,sizeof(int),4,file);
    fwrite(c,sizeof(int),4,file);
    fwrite(d,sizeof(int),4,file);
    fclose(file);
    return 0;
}

subl 打開

0000 0000 0100 0000 0200 0000 0300 0000
0000 0000 0100 0000 0200 0000 0300 0000
0000 0000 ffff ffff feff ffff fdff ffff
0000 0200 0000 0400 0000 0800 0000 1000

仍然,按照我們認知的習慣,需要這樣讀,例如-2
IEEE 754標準下是11111111 11111111 11111111 11111110ffff fffe
倒轉2次得到feff ffff
再如2^17=131072
IEEE 754標準下是00000000 00000010 00000000 000000000002 0000
倒轉2次得到0000 0200

abcd efghab¯¯¯¯|cd¯¯¯¯¯¯¯¯cd¯¯¯¯|efefcd cdab

或許用數字表示更清楚:
1234 567812¯¯¯¯|34¯¯¯¯¯¯¯¯56¯¯¯¯|787856 3412

事實上上面的表示方法是十六進制的表示方法,也就是說上面的12345678實際上是{12}{34}{56}{78}四個字節,我們用ABCD來表示, 則上面的反轉公式就可以簡單地表示爲:
ABCDDCBA

看到這裏應該明白了,其實內存中儲存的就是課本上所教的補碼(整形)和IEEE 756定義的浮點型,爲什麼反過來儲存呢,這是系統決定的,即採用Little EndianBig Endian(這個沒求證過,我以前只知道Little/Big Endian會決定一個字節bit之間順序上的儲存方式,現在看來好像也會決定字節之間順序上的儲存關係)

同時要注意到單個byte在顯示的時候並沒有翻轉過來,也就是可以兩個數字``兩個數字地讀

這樣說來,一開始使用的 od -x 命令其實是幫住用戶把連續的兩個字節倒過來,但感覺這沒必要啊,並不是所有的類型都是兩個字節表示的(如果真是這樣確實是方便了)。難道是爲了方便用戶四個數字``四個數字地讀?

再來拿double練習一下:

上面的C代碼中在合適的位置加入

double e[]={1.0,3.0,100,-100};


fwrite(e,sizeof(double),4,file);

輸出的文件中增加了這樣兩行

0000 0000 0000 f03f 0000 0000 0000 0840
0000 0000 0000 5940 0000 0000 0000 59c0

有了前面的結論直接閱讀之:

  • 取前面8個字節,並反轉之得到 3ff0 0000 0000 0000
  • 變成二進制 0011 1111 1111 {0000}x13
  • 變成IEEE 754double格式0 01111111111 {0}x52
  • 變成十進制數字+1.0×221011023=1 , 完成,正確

  • 取最後8個字節,c059 0000 0000 0000

  • 1100 0000 0101 1001 {0000}x12
  • 1 10000000101 1001{0}x48
  • 1.1001×220+22+2101023=(1100100)2=(4+32+64)=100 ,完成,正確

延伸閱讀
Big and Little Endian

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章