【轉】float類型在內存中的表示

http://www.cnblogs.com/onedime/archive/2012/11/19/2778130.htmlhtml

http://blog.csdn.net/adream307/article/details/7246993web

http://wenku.baidu.com/link?url=Q_SYeQffEjdS1cpMXIRncmmhwKA_o2978-0ei1_gz9ym2vrmmBrSEZArpE6tR4yCB9PEHLG_FHRakijbr9-Y0DIK_MTjBUTKoXUhgIYETB3算法

 

ZC:url

    float f;
    int j = 0x7FFFFFFF;
    memcpy(&f, &i, sizeof(i));

 

1、spa

浮點型變量在計算機內存中佔用4字節(Byte),即32-bit。遵循IEEE-754格式標準。
一個浮點數由2部分組成:底數m 和 指數e。
                          ±mantissa × 2exponent
(注意,公式中的mantissa 和 exponent使用二進制表示)
底數部分 使用2進制數來表示此浮點數的實際值。
指數部分 佔用8-bit的二進制數,可表示數值範圍爲0-255。 可是指數應可正可負,因此IEEE規定,此處算出的次方須減去127纔是真正的指數。因此float的指數可從 -126到128.
底數部分實際是佔用24-bit的一個值,因爲其最高位是e位 ,因此最高位省去不存儲,在存儲中只有23-bit。
到目前爲止, 底數部分 23位 加上指數部分 8位 使用了31位。那麼前面說過,float是佔用4個字節即32-bit,那麼還有一位是幹嗎用的呢?   還有一位,其實就是4字節中的最高位,用來指示浮點數的正負,當最高位是1時,爲負數,最高位是0時,爲正數。
   浮點數據就是按下表的格式存儲在4個字節中:
                    Address+0       Address+1              Address+2              Address+3
Contents     SEEE EEEE     EMMM MMMM     MMMM MMMM     MMMM MMMM      S: 表示浮點數正負,1爲負數,0爲正數
      E: 指數加上127後的值的二進制數
      M: 24-bit的底數(只存儲23-bit)
主意:這裏有個特例,浮點數 爲0時,指數和底數都爲0,但此前的公式不成立。由於2的0次方爲1,因此,0是個特例。固然,這個特例也不用人爲去解決,編譯器會自動去識別。


      經過上面的格式,咱們下面舉例看下4.5在計算機中存儲的具體數據:
                    Address+0                 Address+1               Address+2            Address+3
Contents        0x40                         0x90                           0x00                      0x00     接下來咱們驗證下上面的數據表示的究竟是不是4.5,從而也看下它的轉換過程。
因爲浮點數不是以直接格式存儲,他有幾部分組成,因此要轉換浮點數,首先要把各部分的值分離出來。
                  Address+0      Address+1                  Address+2             Address+3
格式         SEEEEEEE     EMMMMMMM       MMMMMMMM     MMMMMMMM
二進制     01000000         10010000               00000000                00000000
16進制     40                         90                            00                            00
       可見:
       S: 爲0,是個正數。
       E:爲 10000001   轉爲10進製爲129,129-127=2,即實際指數部分爲2。
       M:爲 00100000000000000000000。 這裏,在底數左邊省略存儲了一個1,使用 實際底數表示爲 1.00100000000000000000000
       到此,咱們吧三個部分的值都拎出來了,如今,咱們經過指數部分E的值來調整底數部分M的值。調整方法爲:若是指數E爲負數,底數的小數點向左移,若是指數E爲正數,底數的小數點向右移。小數點移動的位數由指數E的絕對值決定。
      這裏,E爲正2,使用向右移2爲即得:
      100.100000000000000000000
至次,這個結果就是4.5的二進制浮點數,將他換算成10進制數就看到4.5了,如何轉換,看下面:
小數點左邊的100 表示爲 (1 × 22) + (0 × 21) + (0 × 20), 其結果爲 4。
小數點右邊的 .100… 表示爲 (1 × 2-1) + (0 × 2-2) + (0 × 2-3) + ... ,其結果爲.5 。
以上二值的和爲4.5, 因爲S 爲0,使用爲正數,即4.5 。
因此,16進制 0x40900000 是浮點數 4.5 。

上面是如何將計算機存儲中的二進制數如何轉換成實際浮點數,下面看下如何將一浮點數裝換成計算機存儲格式中的二進制數。
舉例將17.625換算成 float型。
首先,將17.625換算成二進制位:10001.101   ( 0.625 = 0.5+0.125, 0.5即 1/2, 0.125即 1/8 若是不會將小數部分轉換成二進制,請參考其餘書籍。) 再將 10001.101 向右移,直到小數點前只剩一位 成了 1.0001101 x 2的4次方(由於右移了4位)。此時 咱們的底數M和指數E就出來了:
底數部分M,由於小數點前必爲1,因此IEEE規定只記錄小數點後的就好,因此此處底數爲   0001101 。
指數部分E,實際爲4,但須加上127,固爲131,即二進制數 10000011 
符號部分S,因爲是正數,因此S爲0.
綜上所述,17.625的 float 存儲格式就是:
0 10000011 00011010000000000000000
轉換成16進制:0x41 8D 00 00
因此,一看,仍是佔用了4個字節。.net

 

2、3d

float一共32位,其結構定義以下:code

|-------- 31 -------|------------ 30-23 ------------ |------------ 22-0 ------------|orm

   符號位(sign)         指數部分(exp)                       小數部分(mag)htm

sign:符號位就一位,0表示正數,1表示負數

exp: 指數部分,無符號正數

mag:小數部分,定點小數,小數點在最左邊。

float的表達式 :  pow(-1,sign)  *  (1+mag)  * pow(2,exp-127)

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc,char *argv[])
{
    float f;
    int i;
    int sign;
    int exp;
    int mag;
    float d_mag;
    float f2;

    sscanf(argv[1],"%f",&f);
    //f=-0.12;
    i = *(int*)&f;
    sign = (i>>31)&0x01;
    exp = (i>>23)&0xFF;
    mag = i&0x7FFFFF;
    d_mag = 1.0f*mag/0x800000;
    f2 = (sign==0?1:-1)*(1+d_mag)*pow(2,exp-127);
    printf("float:f=%f\n",f);
    printf("sign=%X,exp=%X,mag=%X\n",sign,exp,mag);
    printf("float:f2=%f\n",f2);
    return 0;
}

 

參考文獻:http://en.wikipedia.org/wiki/IEEE_754-1985

 

3、

 

進制的算法:

 

 

整數

 

 

整數的二進制算法你們應該很熟悉,就是不斷的除以

2

取餘數,而後將餘數倒序排

列。

 

 

 

小數

 

 

小數的二進制算法和整數的大體相反,就是不斷的拿小數部分乘以

2

取積的整數部

分,而後正序排列。好比求

0.9

的二進制:

 

 

0.9*2=1.8 

 

 

0.8*2=1.6 

 

 

0.6*2=1.2 

 

 

0.2*2=0.4 

 

 

0.4*2=0.8 

 

 

0.8*2=1.6 

 

 

… … 

 

如此循環下去。所以我麼獲得的二進制小數也是無限循環的:

0.11100110011... 

 

從小數的二進制算法中咱們能夠知道,若是想讓這種算法中止,只有在小數部分是

0.5

的時候才能夠,可是很不幸,這類的小數不多。因此大部分小數是很難用二進制

來精確表示的。

 

 

 

------------------------

我是分割線

------------------------------

 

 

OK

,有了上面的知識,咱們進入正題:看看

float

類型在內存中是如何表示的。

 

 

 

 

float

類型又稱爲單精度浮點類型,在

 

 

 

IEEE 754-2008

 

 

 

中是這樣定義它的結構的:

 

 

 

  S 

 

    EEEEEEEE 

 

     FFFFFFFFFFFFFFFFFFFFFFF 

 

31 

  30 

       23 

   22 

                              0

 

 

 

float

類型總共

4

個字節

——

32

位:

 

 

1.

符號位

 

其中最左邊的爲符號位,

0

爲正,

1

爲負。

 

 

2.

指數

 

接下來的

E

是指數,一共

8

位,也用二進制來表示。

 

 

3.

尾數

 

最後的

F

是小數部分,

尾數正是由這

23

位的小數部分

+1

位組成的。

這個稍後解釋)

 

 

 

這裏咱們須要多說一下指數。雖然指數也是用

8

位二進制來表示的,可是

IEEE

在定義它的時候

作了些手腳,使用了偏移來計算指數。

 

 

 

 

IEEE

 

規定,在

 

float

 

類型中,用來計算指數的偏移量爲

127

 

。也就是說,若是你的指數實際是

0

 

 

那麼在內存中存的就是

 

0+127=127

 

的二進制。稍後咱們來看這個到底如何使用。

 

 

 

 

 

好了,看了這麼多,咱們該演示一下計算機如何將一個十進制的實數轉換爲二進制的。就拿

 

6.9

 

這個數字來舉例吧。

 

-_-||!

 

 

 

 

 

首先,咱們按照上面說的方法,分別將整數和小數轉換成對應的二進制。這樣

6.9

 

的二進制表示

 

就是

 

110.1110011001100...

。這裏就看出來了,

 

6.9

 

轉換成二進制,小數部分是無限循環的,這在

 

如今的計算機系統上是沒法精確表示的。這是計算機在計算浮點數的時候經常不精確的緣由之

 

一。

 

 

 

 

其次,將小數點左移(或右移)到第一個有效數字以後。說的通俗些,就是把小數點移到第一個

 

1

以後。這樣的話,對於上面

 

 

110.1110011001100...

 

咱們就須要把小數點左

 

2

 

位,獲得

 

1.101110011001100...

 

 

 

 

 

 

接下來的事情就有意思了。

首先咱們把獲得的

 

1.101110011001100..

這個數,

 

從小數點後第一位開

 

始,數出

 

23

 

個來,填充到上面

 

float

內存結構的尾數部分(就是那一堆

 

F

 

的地方),咱們這裏數

 

出來的就是

 

10111001100110011001100

。這裏又要發生一次不精確了,小數點後超出

 

 

 

23

 

位的部

分都將被捨棄,太慘了。

 

 

 

 

 

不過,

 

這裏有一個可能讓你們以爲特別坑爹的事情,

 

就是小數點前面的

 

1

 

也不要了。仔細看看上

面的內存結構,確實沒有地方存放這個

 

1

 

。緣由是這樣的:

 

IEEE

 

以爲,既然咱們你們都約定把

 

小數點移動到第一個有效數字以後,那也就默認小數點前面必定有且只有一個

1

 

,因此把這個

 

1

 

存起來也浪費,乾脆就不要了,之後你們都這麼默契的來就好。這也是爲何我上面說尾數是

 

23

 

 

+1

位的緣由。

 

 

 

 

 

填充完尾數,

 

該填充指數了。

這個指數就是剛纔咱們把小數點移動的位數,

 

左移爲正,

 

右移爲負,

 

再按照上面所說的偏移量算法,咱們填充的指數應該是

 

2+127=129

 

。轉換成

8

 

位二進制就是

10000001

 

 

 

 

 

最後,根據這個數的正負來填充符號位。咱們這裏是正數,因此填

 

0

 

。這樣

 

6.9

 

的在內存中的存

 

儲結果就出來了:

 

 

 

 

 

 10000001 

 10111001100110011001100

 

 

總結一下,實數轉二進制

float

類型的方法:

 

 

A. 

分別將實數的整數和小數轉換爲二進制

 

B. 

左移或者右移小數點到第一個有效數字以後

 

C. 

從小數點後第一位開始數出

23

位填充到尾數部分

 

 

D. 

把小數點移動的位數,左移爲正,右移爲負,加上偏移量

127

,將所得的和轉換爲二進制填

充到指數部分

 

E. 

根據實數的正負來填充符號位,

0

爲正,

1

爲負

 

若是須要把

float

的二進制轉換回十進制的實數,只要將上面的步驟倒着來一邊就好了

相關文章
相關標籤/搜索