float數據類型及double數據類型整理

float數據類型在內存中的存儲形式介紹:

  float在內存中的存儲遵循IEEE 754標準。在C/C++中,float類型佔4個字節即32位 , 這32位分成了3部分:

       符號位:轉化成二進制後,第31位。 0代表正數,1代表負數

       階碼:30-23位,轉化成規格化的二進制之後與127之和

       尾數:22-0位

   

例如:13.625在內存中的存儲

       首先將13.625轉化成二進制

          整數部分除2取餘,直到商爲0停止 。最後讀數時,從最後一個餘數讀起,一直到最前面的一個餘數

                   

       所以整數部分13的二進制位  1101;
       小數部分乘2取整,然後從前往後讀。

         0.625*2 = 1.25        取整      1

         0.25*2   = 0.5          取整      0

         0.5*2    = 1             取整      1

       所以小數部分的二進制  101

       然後將 1101.101的小數點向左移至小數點前只有一個1,即左移3位 (這裏爲二進制的特定表示方法,將整數部分劃爲1)

       階碼就是3+127 = 130  即:1000 0010

      符號位:0

      尾數 :因爲小數點前必爲一,所以記錄小數點後面的數即可 101101

       0100 0001 0101 1010 0000 0000 0000 0000   

       轉換成16進制後爲 41 5A 00 00  


float/double類型數據在內存中中存儲格式

float/double類型數據在計算機是如何存儲的呢?

它們是ieee standard 754的存儲方式。 譬如float數,第一位是符號位,然後是8位指數位,然後是23位尾數;double雙精度格式爲8字節64位,由三個字段組成:52位小數f,11位偏置指數e,以及1位符號s,這些字段連續存儲在兩個32位字中。

存儲結構

類型 符號位 指數位 尾數位
float 0 0xff 0x7fffff
double 0 0x7ff 0xfffffffffffff

注意

上面的存儲結構,由於字節太多,所以後面使用的十六進制表示,7代表3位,f代表4位

浮點類型

從存儲結構和算法上來講,double和float是一樣的,不一樣的地方僅僅是float是32位的,double是64位的,所以double能存儲更高的精度以及更大的數值。float表示的正數範圍是3.40282346638528859811704183484516925440e+38~1.401298464324817070923729583289916131280e-45,double的正數範圍是1.797693134862315708145274237317043567981e+308~4.940656458412465441765687928682213723651e-324

【注:個人認爲,從階碼上移位來算,整數部分的確可以表示這麼大的數據範圍,但是從卻受到後面尾數的限制,float的有效位數只有6-7位,double的有效位數爲15-16位(至於具體爲什麼是6-7位、15-16位看下面的總結部分),所以感覺上面表示這麼大的數據範圍實際上意義不大。】

  • 可以看出來double的表示的範圍比float大,而且由於尾數增加,實際上,精確度也比float高,但這樣的優勢帶來的就是更低的計算效率,雖然個人覺得不論是float還是double計算效率都被整形完爆,所以能夠用整型操作,就儘量不要用浮點型。

  • 另外一個主要注意的則是,我們可以看到這裏該數的表示範圍並不像整形那樣,直接可以表示0,而是是一個很大到一個很接近0的數值,所以很多情況下浮點數判斷是否爲0,不是直接跟0比較是不是相等,而是約定一個很小的數,如果小於這個數,就等於0.

實際在內存中的存儲順序

任何數據在內存中都是以二進制(0或1)順序存儲的,每一個1或0被稱爲1位,而在x86CPU上一個字節是8位。比如一個16位(2字節)的short int型變量的值是1000,那麼它的二進制表達就是:00000011 11101000。由於Intel CPU的架構是小尾端表示,它是按字節倒序存儲的,那麼就因該是這樣:11101000 00000011,這就是定點數1000在內存中的結構。 (如果這裏不明白爲什麼這樣,可以搜索大尾端小尾端概念)

目前C/C++編譯器標準都遵照IEEE制定的浮點數表示法來進行float,double運算。這種結構是一種科學計數法,用符號、指數和尾數來表示,底數定爲2——即把一個浮點數表示爲尾數乘以2的指數次方再添上符號。下面是具體的規格:

類型 符號位 階碼 尾數 長度
float 1 8 23 32
double 1 11 52 64

實戰:十進制轉十六進制

下面以double38414.4爲例:

  1. 把整數部和小數部分開處理:整數部直接化十六進制:960E。
  2. 小數的處理: 0.4=0.5*0+0.25*1+0.125*1+0.0625*0+……

你會發現第二步根本是坑爹嘛,根本算不完,那麼該怎麼辦呢?加上前面整數的精度960E,你只需要算夠53位就行了(最高位的1不寫入內存)。手工算到53位是:38414.4(10)=1001011000001110.011001100110011001100110011001100110011(2) 
科學記數法:1.001……乘以2的15次方。

(注意指數是15,這裏的指數是2的次方,不是10的次方)

然後看階碼,一共11位,可以表示範圍是-1024 ~ 1023。因爲指數可以爲負,爲了便於計算,規定都先加上1023,在這裏,

15+1023=1038。二進制表示爲:100 00001110

符號位:正—— 0 !

合在一起(尾數二進制最高位的1不要):

01000000 11100010 11000001 11001101 01010101 01010101 01010101 01010101

假定機器爲小尾端,字節倒序存儲的十六進制數就是: 
55 55 55 55 CD C1 E2 40

協議參考網址

IEEE Standard 754 for Binary Floating-Point Arithmetic

http://www.wikilib.com/wiki?title=IEEE_754&variant=zh-sg

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

總結:

1 範圍

float和double的範圍是由指數的位數來決定的。

float的指數位有8位,而double的指數位有11位,分佈如下:

float:

1bit(符號位)

8bits(指數位)

23bits(尾數位)

double:

1bit(符號位)

11bits(指數位)

52bits(尾數位)

於是,float的指數範圍爲-127~+128,而double的指數範圍爲-1023~+1024,並且指數位是按補碼的形式來劃分的。其中負指數決定了浮點數所能表達的絕對值最小的非零數;而正指數決定了浮點數所能表達的絕對值最大的數,也即決定了浮點數的取值範圍。

float的範圍爲-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的範圍爲-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。

2 精度

float和double的精度是由尾數的位數來決定的。浮點數在內存中是按科學計數法來存儲的,其整數部分始終是一個隱含着的“1”,由於它是不變的,故不能對精度造成影響。

float:2^23 = 8388608,一共七位,這意味着最多能有7位有效數字,但絕對能保證的爲6位,也即float的精度爲6~7位有效數字;

【也可以這麼算,0.000001的精度爲10^(-6), 2^20 = 1048576; 1/1048576的精度高於10^(-6), 但是23位不夠表示10^(-7),所以爲有效位數爲6-7位;】

double:2^52 = 4503599627370496,一共16位,同理,double的精度爲15~16位。

所以,float數據類型受到有限的有效位數限制,不能表示精度高的浮點型數據;


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