1. 程式人生 > >機器中的浮點數表示

機器中的浮點數表示

       在初學C語言時,一直體會不到所謂的浮點數容易造成誤差,最近看到一篇關於浮點數的文章,加上現在的學習,對浮點數的內部儲存方式有了更加深入的理解,於是也漸漸理解了浮點數的誤差。

        相比int等整型,float等浮點型別的表示和儲存較為複雜,但它又是一個無法迴避的話題,那麼就有必要對浮點一探究竟了。在計算機中,一般用IEEE浮點近似表示任意一個實數,那麼它實際上又是如何表示的呢?

已知:在機器儲存中,我們是利用定點數來表示浮點數的,顧名思義,定點數中小數點的位置是預設的(全小數的小數點在最左邊,全整的預設在最右邊),而我們下面介紹的IEEE浮點近似表示中:全小數使用原碼錶示,全整使用補碼錶示,因為原碼中,數軸關於原點對稱,可以用來表示“0”兩端對稱的數,而補碼是環狀數軸,計算方便,因此用來表示整數位。

以 F = (-1)^S*M*2^E的形式近似表示一個數。並且將浮點數的位表示劃分為三個欄位:

符號(sign)s決定這個數是負數(s=1)還是正數(s=0)。可以用一個單獨的符號s直接編碼符號s。
尾數(signficand)M是一個二進位制小數。(全定點小數)
階碼(exponent)E的作用是對浮點數加權,這個權重是2的E次冪(可能是負數)。k位的階碼欄位 編碼階碼E。

在單精度浮點格式(c語言的float)中,s,exp和frac欄位分別為1位,8位和23位,而雙精度浮點格式(c語言中的double)中,s,exp和frac欄位分別為1位,11位和52位。(在這裡也可以看出來,機器的位數不變,而浮點數佔位很多且疏散)

一個浮點數的常見位元位表示如下:

單精度:float
s(31)    exp(30~23)    frac(22~0)
雙精度:double
s(53)    exp(62~52)    frac(51~0)

而根據exp的值,被編碼的值可以分為三大類不同的情況。下面進行一一解釋。

情況1:規格化的值

即最普遍的情況,當exp,即階碼域既不為全0,也不為全1的情況。在這種情況下,階碼欄位解釋為以偏置(biased)形式表示有符號整數,即E=exp-Bias,exp是無符號數(1~254)。Bias是一個等於的偏置值,對於單精度來說,k=23,Bias=127,因此E的範圍是-126~+127。

frac被描述為小數值,且0≤frac<1,其二進位制表示為0.frac。尾數定義為 M=1+frac ,則M=1.frac。那麼就有1≤M<2,由於總是能夠調整階碼E,使得M在範圍1≤M<2,所以不需要顯示的表示它,這樣還能獲得一個額外的精度位。也就是說,在計算機內部儲存M時,預設這個數的第一位總是1,因此可以被捨去,只儲存後面的frac部分,等到讀取的時候,再把第一位的1加上去。

情況2:非規格化的值

當exp,即階碼域為全0時,所表示的數便為非規格化的值,該情況下的階碼值E=1-Bias(注:為從非格式化值轉換到格式化值提供了一種方法)。尾數M=frac
非規格化的數有兩個作用。

表示數值0。格式化數中,我們總使得M≥1,因此就無法表示0。而階碼全0時,且尾數也全0時,就可以表示0了。
表示接近0.0的數。它所表示的值分佈地接近於0.0,該屬性成為逐漸溢位。

情況3:特殊值

有兩種

階碼全為1,小數域全為0。它得到值為 +∞(s=0)或-∞(s=1),它在計算機中可以表示溢位的結果,例如兩個非常大的數相乘。
階碼全為1,小數域不全為0。它得到值為NaN(Note a Number)。它在計算機中可以表示非法的數,例如計算根號-1時的值。

浮點數的範圍和有效位

對於浮點數,其能表示的數值範圍和其有效位如下

型別    位元位    數值範圍    有效位
float    32    -3.410^38~+3.410^38    6~7位
double    64    -1.710^-308~1.710^308    15~16位
long double    128    -1.210^-4932~1.210^4932    18~19位

可見同位元位數的整型(例如int)要比浮點數(例如float)能表示的數值範圍要小很多,但是需要注意的,雖然浮點數能表示的範圍大,但是 它卻不能精確表示在其範圍內的所有實數,也就是說,它只能保證有效位的值是精確的,當表示的數值(小數部分)超過有效位時,所表示的數是無法保證精確的,甚至可以說是錯誤的。

浮點數的有效位:

有效位也可以理解為我們常說的精度。浮點數的精度是由尾數的位數來決定的。

對於單精度(float),它的尾數為23位,而2^23=8388608,共7位,也就是說最多能有7位有效數字,但至少能保證6位,因此其有效位為6~7位。

我們可以通過位數發現:0.0000001和0.0000002之間的其他數是沒有辦法通過單精度浮點數來精確表示的(這裡引入0的概念,即浮點數表示的0有可能只是一個趨近於0的值,實際運算的誤差可能會很大),也就是說,只有到小數點後面7位的值才是精確的,同理,觀察b和c的結果,0.0000002到0.0000004之間的其他數也是不能通過單精度浮點數精確表示的,更不幸地是,這之間的數,甚至只能精確到第6位。

這也就有了單精度浮點數的有效位為6~7位的結論。根據相似的方法,我們同樣可以得到雙精度浮點數的有效位為15~16位的結論,這裡不再贅述。

關於浮點數,需要再說幾句:

1、在二進位制,第一個有效數字必定是“1”,因此這個“1”並不會儲存。
2、浮點數不能精確表示其範圍內的所有數。

3、可精確表示的數不是均勻分佈的,越靠近0越稠密(所以也就是說無法表示所有的實數)。
4、預設舍入方式為向偶舍入,也被稱為最接近的值舍入。
 

(由於之前沒有怎麼理解,因此上面存在一些錯誤,非常抱歉,博主會盡快修改的)