浮點數儲存的位元組格式

2021-04-30 06:27:23 字數 4264 閱讀 7172

--該文章為多篇論述浮點數的文章合體

目前已知的所有的c/c++編譯器都是按照ieee(國際電子電器工程師協會)制定的ieee   浮點數表示法來進行運算的。這種結構是一種科學表示法,用符號(正或負)、指數和尾數來表示,底數被確定為2,也就是說是把乙個浮點數表示為尾數乘以2的指數次方再加上符號。

位址        +0          +1           +2           +3

內容    seee eeee    emmm mmmm     mmmm mmmm    mmmm mmmm

這裡s 代表符號位,1是負,0是正

e 偏移127的冪,二進位制階碼=(eeeeeeee)-127。

m 24位的尾數儲存在23位中,只儲存23位,最高位固定為1。此方法用最較少的位數實現了

較高的有效位數,提高了精度。

零是乙個特定值,冪是0 尾數也是0。其在記憶體中存放的為0x00 0x00 0x00 0x00

現在讓我們按照ieee浮點數表示法,一步步的將float型浮點數12345.0f轉換為十六進製制**。在處理這種不帶小數的浮點數時,直接將整數部轉化為二進位制表示:1   1110 0010   0100 0000也可以這樣表示:1 1110 0010 0100 0000.0然後將小數點向左移,一直移到離最高位只有1位,就是最高位的1:1.11100010010000000一共移動了16位,在布耳運算中小數點每向左移一位就等於在以2為底的科學計算法表示中指數+1,所以原數就等於這樣:1.11100010010000000   *   (   2   ^   16   )好了,現在我們要的尾數和指數都出來了。顯而易見,最高位永遠是1,因為你不可能把買了16個雞蛋說成是買了0016個雞蛋吧?(呵呵,可別拿你買的臭雞蛋甩我~),所以這個1我們還有必要保留他嗎?(眾:沒有!)好的,我們刪掉他。這樣尾數的二進位制就變成了:11100010010000000最後在尾數的後面補0,一直到補夠23位:11100010010000000000000(md,這些個0差點沒把我數的背過氣去~)  

再回來看指數,一共8位,可以表示範圍是0   -   255的無符號整數,也可以表示-128   -   127的有符號整數。但因為指數是可以為負的,所以為了統一把十進位制的整數化為二進位制時,都先加上127,在這裡,我們的16加上127後就變成了143,二進位制表示為:10001111  

12345.0f這個數是正的,所以符號位是0,那麼我們按照前面講的格式把它拼起來:  

0   1000 1111   1110 0010 0100 0000 0000 000  

0100 0111   1111 0001   0010 0000   0000 0000  

再轉化為16進製為:47   f1   20   00,最後把它翻過來,就成了:00   20   f1   47。  

現在你自己把54321.0f轉為二進位制表示,自己動手練一下!

有了上面的基礎後,下面我再舉乙個帶小數的例子來看一下為什麼會出現精度問題。  

按照ieee浮點數表示法,將float型浮點數123.456f轉換為十六進製制**。對於這種帶小數的就需要把整數部和小數部分開處理。整數部直接化二進位制:100100011。小數部的處理比較麻煩一些,也不太好講,可能反著講效果好一點,比如有乙個十進位制純小數0.57826,那麼5是十分位,位階是1/10;7是百分位,位階是1/100;8是千分位,位階是1/1000……,這些位階分母的關係是10^1、10^2、10^3……,現假設每一位的序列是,在這裡就是5、7、8、2、6,而這個純小數就可以這樣表示:n   =   s1   *   (   1   /   (   10   ^   1   )   )   +   s2   *   (   1   /   (   10   ^   2   )   )   +   s3   *   (   1   /   (   10   ^   3   )   )   +   ……   +   sn   *   (   1   /   (   10   ^   n   )   )。把這個公式推廣到b進製純小數中就是這樣:  

n   =   s1   *   (   1   /   (   b   ^   1   )   )   +   s2   *   (   1   /   (   b   ^   2   )   )   +   s3   *   (   1   /   (   b   ^   3   )   )   +   ……   +   sn   *   (   1   /   (   b   ^   n   )   )  

天哪,可惡的數學,我怎麼快成了數學老師了!現在乙個二進位制純小數比如0.100101011就應該比較好理解了,這個數的位階序列就因該是1/(2^1)、1/(2^2)、1/(2^3)、1/(2^4),即0.5、0.25、0.125、0.0625……。乘以s序列中的1或著0算出每一項再相加就可以得出原數了。現在你的基礎知識因該足夠了,再回過頭來看0.45這個十進位制純小數,化為該如何表示呢?現在你動手算一下。

我想你已經迫不及待的想要看答案了,因為你發現這跟本算不出來!來看一下步驟:1   /   2   ^1位(為了方便,下面僅用2的指數來表示位),0.456小於位階值0.5故為0;2位,0.456大於位階值0.25,該位為1,並將0.45減去0.25得0.206進下一位;3位,0.206大於位階值0.125,該位為1,並將0.206減去0.125得0.081進下一位;4位,0.081大於0.0625,為1,並將0.081減去0.0625得0.0185進下一位;5位0.0185小於0.03125,為0……問題出來了,即使超過尾數的最大長度23位也除不盡!這就是著名的浮點數精度問題了。不過我在這裡不是要給大家講《數值計算》,用各種方法來提高計算精度,因為那太龐雜了,恐怕我講上一年也理不清個頭緒啊。我在這裡就僅把浮點數表示法講清楚便達到目的了。  

ok,我們繼續。嗯,剛說哪了?哦對對,那個數還沒轉完呢,反正最後一直求也求不盡,加上前面的整數部算夠24位就行了:1111011.01110100101111001。某bc問:「不是23位嗎?」我:「倒,不是說過了要把第乙個1去掉嗎?當然要加一位嘍!」現在開始向左移小數點,大家和我一起移,眾:「1、2、3……」好了,一共移了6位,6加上127得131(怎麼跟教小學生似的?呵呵~),二進位制表示為:10000101,符號位為……再……不說了,越說越囉嗦,大家自己看吧:  

0     10000101     11101101110100101111001  

42     f6     e9     79  

79     e9     f6     42  

下面再來講如何將純小數轉化為十六進製制。對於純小數,比如0.0456,我們需要把他規格化,變為1.***x   *   (2   ^   n   )的型式,要求得純小數x對應的n可用下面的公式:  

n   =   int(   1   +   log   (2)x   );  

0.0456我們可以表示為1.4592乘以以2為底的-5次方的冪,即1.4592   *   (   2   ^   -5   )。轉化為這樣形式後,再按照上面第二個例子裡的流程處理:  

1.   01110101100011100010001  

去掉第乙個1  

01110101100011100010001  

-5   +   127   =   122  

0     01111010     01110101100011100010001  

最後:  

11   c7   3a   3d  

另外不得不提到的一點是0.0f對應的十六進製制是00   00   00   00,記住就可以了。  

最後貼乙個可以分析並輸出浮點數結構的函式源**,有興趣的自己看看吧:  

//   輸入4個位元組的浮點數記憶體資料  

void   decodefloat(   byte   pbyte[4]   )  

ulexponent   -=   127;  

cout   <<   "指數(十進位制):"   <<   ulexponent   <<   endl;  

bittemp   =   bitall;  

bittemp   <<=   9;  

float   fmantissa   =   1.0f;  

for   (   int   i   =   0;   i   <   23;   i++   )  

cout   <<   "尾數(十進位制):"     <<   fmantissa   <<   endl;  

float   fpow;  

if   (   ulexponent   >=   0   )  

else  

cout   <<   "運算結果:"   <<   fmantissa   *   fpow   <<   endl;  

}

浮點數 儲存

關鍵字 體系結構 ieee754 浮點數 儲存 main 如果不執行上面的 讓我們來直接判斷,輸出的結果會是什麼?而在你執行程式之後,結果卻很讓人詫異 123.456001。為什麼會是123.456001?有六位小數可以理解,最後那個1是為何?有很多人解釋說最後那個1是亂碼,隨機的。嘿嘿 其實無論你...

浮點數的儲存

浮點數在計算機中的儲存格式 符號位 指數字 尾數字 符號位 指數字 尾數字 float 1位 8位 23位 共32位 double 1位 11位 52位 共64位 任何浮點數都可表示為 1.m 2e 符號位 sign 表示式中的 0表示正數,1表示負數。指數字 exponent 表示式中的e,指數字...

浮點數的儲存

浮點數 float或double 在儲存方式上都遵從ieee的規範,float遵從的是ieee r32.24,資料佔據32bit,double遵從的是r64.53,資料占用64bit。8.25 41 04 00 00 高位在前 0100 0001 0000 0100 0000 0000 0000 0...