準確詳解:C/C++ float、double資料型別的表示範圍及精度

black_kyatu發表於2018-02-05

 

 今天覆習C++遇到了float、double資料型別的表示範圍及精度問題,花費了一些時間重新梳理了一遍,鑑於網上很多文章寫的並不清晰,並且有不少疏漏錯誤之處,特結合個人理解仔細整理如下。

  要弄清楚這個問題,首先要搞清楚浮點數在記憶體中的儲存方式。浮點數,區別於定點數,指的是小數點位不確定的的資料型別,其原理是將一個浮點數a用兩個數m(尾數)和e(指數)來表示:a = m × b^e。其中的b為選取的基數。科學計數法就是一種特殊形式的浮點數。

  在計算機二進位制表示中,浮點數採用2作為基數,規定尾數的範圍為1.0~2.0之間。

 以float型別為例,根據最廣泛採用的IEEE754標準規定,float資料型別長度為32位,其中最高位為符號位,中間8位為指數位,最後23位作為尾數位。

  最高位符號位通過0/1來區分正負,0正1負;指數位則規定採用移碼的形式儲存,這樣可以保證指數部分為無符號數,方便比較大小。移碼錶示法是在數X上增加一個偏移量來定義的,如果機器字長為n,規定偏移量為2^(n-1),對於8位補碼-128~127,可得到對應的階碼錶示為0~255,其中全0和全1分別用來表示0和無窮大,故規定1~254用來表示規範數字,即對應指數範圍從-126127;尾數部分統一規定為1.0-2.0之間,最高位必然為1,故可以省略,所以尾數部分從小數點後算起,最小可以取到1,最大則取到二進位制1.1...1(小數點後23位),即取到2-2^-23,可近似約等於2。故得到float絕對值的最大值取到2^127*(2-2^-23)約等於2^128=3.4E+38。加上符號之後可得float表示範圍為(-3.4E+38)~(3.4E+38)。當然實際是取不到的,開區間。絕對值最小則可以取到2^-127*1,即為1.175E-38。

接下來解釋精度。由於尾數部分位數是固定的小數點後23位,23位所能表示的最大數是2^23−1=8388607,所以十進位制的尾數部分最大數值是8388607,也就是說尾數數值超過這個值之後,float將無法精確表示,所以float最多能表示小於8388607的小數點後7位,但絕對能保證的為6位,也即float的十進位制的精度為為6~7位。

double資料型別的推算過程和上述同理,唯一的區別在於尾數由23位擴充套件到52位,階碼由8位增加到了11位,計算方法不變。所以double的階碼(移碼錶示)為1~2046,偏移量為1023,故指數範圍為-1022~1023,得表示範圍為(2^1023*2)~(-2^1023*2)即為-1.7E+308~1.7E+308,絕對值最小可以取到2^-1022,精度則為2^52-1=4503599627370495,為16位。所以精度最高位16位,一定可以保證15位。

 

相關文章