浮點數運算的機器偏差分析

用一個浮點數相加的例子來演示計算機在計算時所產生的偏差。網站

 

在Python中,用0.2+0.4 會獲得0.6000000000000001。編碼

 

浮點數簡介blog

浮點數的表示方法:目前流行的浮點數標準是IEEE754。用64個bit來表示雙精度。get

 

 

首位爲符號位s,0表明正,1表明負。it

接下來的11位表明指數,將其理解爲一個無符號的數字e,例如,00000000011就表明3。定義指數(階碼)M和偏置Bias,其中偏置,定義,容易看出E的範圍爲-1022到+1023。對於單精度,。二進制

最後的52位是編碼尾數M,第一位的權重是1/2,第二位的權重是1/4…  第52位的權重是。這裏有一個隱藏位,在首位以前,表明1.所以M的範圍其實是. 當52位全爲0時,M爲1 當全爲1時,M很是接近2,但還差了一個方法

 

浮點數. M在1到2之間,E在到,這二者配合不管是精度仍是範圍都足夠大了。im

 

浮點數加法(以0.2+0.4爲例)總結

浮點數加法的計算步驟:浮點數有本身的一套計算方法,如下藉助例子詳細闡述,總之核心思想就是保持階碼一致,當須要移位的時候,就拋棄掉尾數的最後一位,由於這一位的權重最小,但就是拋棄尾數的最後幾位致使了偏差。db

 

對階&移位-->有效數求和-->規格化-->舍入處理-->溢出判斷.

以0.2+0.4爲例逐步分析。

首先,利用http://www.binaryconvert.com  將0.2和0.4轉換爲二進制表示,以後從二進制到十進制的逆轉換一樣是由這個網站完成的。

0.2:0 01111111100 1001100110011001100110011001100110011001100110011010

0.4:0 01111111101 1001100110011001100110011001100110011001100110011010

爲了下面闡述方便,直接將隱藏位也一塊兒寫出來。

0.2:0 01111111100 11001100110011001100110011001100110011001100110011010

0.4:0 01111111101 11001100110011001100110011001100110011001100110011010

 

簡單check一下,能夠看出0.2的階碼E=-3,也就是1/8,乘上M後能夠獲得0.2;同理0.4的階碼E=-2.

 1.     對階&移位

對階:先求階差,明顯0.2的階碼比0.4的階碼小1.

移位:小碼向大碼看齊,即將0.2的階碼變成-2,同時將尾數右移一位。這個操做其實就是讓階碼+1,致使原數V擴大兩倍,同時尾數右移一位,致使原數V縮小兩倍。兩者相互抵消。要注意在移動尾數時要連隱藏位一塊兒移動,同時拋棄末位。這樣一來0.2變爲:

0.2:0 01111111101 01100110011001100110011001100110011001100110011001101

 2.     有效數求和

將0.2和0.4的尾數求和,包含隱藏位

0.2:01100110011001100110011001100110011001100110011001101

0.4:11001100110011001100110011001100110011001100110011010

一樣利用一個小網站http://www.99cankao.com  來實現這一計算,計算結果已通過手動check,爲:

100110011001100110011001100110011001100110011001100111

有5位。

 3.     規格化

雙精度數字只容許尾數爲52位,因此上述求和的數字要進行規格化,即將原來的大階碼(-2)加一,變成-1,即01111111110

同時將尾數和右移,與前面移位中相似,階碼+1讓V乘以2,尾數右移讓V除以2。但要注意此時右移是不包括隱藏位的,簡單分析一下緣由:

若是不進行規格化,至關於:

100110011001100110011001100110011001100110011001100111

中,10的權重爲1,也即換位十進制爲1*2+0+1=2,再加上後面的小數,咱們這裏假設爲0.4(數字隨便取的,只爲了說明方便)。那麼此時尾數M=2.4. 爲了使其回到本來的浮點數表示,咱們將階碼加一,那麼相應的尾數就要除以2,變成1.2。在浮點數表示中,隱藏位始中給出一個1,就須要尾數給出0.2,這樣才能獲得1.2。那麼天然地,100110011001100110011001100110011001100110011001100111中,黑色部分給出0.4,將其右移一位,拋棄末位,就能夠獲得0.2。

綜上所述,規格化時尾數的移位不包括隱藏位,可是第一步移位的時候要帶上隱藏位,緣由是類似的,這裏就不展開了。

 4.     舍入處理

在對0.2規格化時,100110011001100110011001100110011001100110011001100111,末位是1,IEEE754的策略是0舍1入,所以去掉隱藏位,初位前加0,拋棄末位,並加一後變爲:

0011001100110011001100110011001100110011001100110100

 5.     溢出處理

整合獲得最後的結果爲

0 01111111110 0011001100110011001100110011001100110011001100110100

這就是咱們最後獲得的0.2+0.4得二進制表示,將其轉換爲十進制看一下結果:

0011111111100011001100110011001100110011001100110011001100110100

能夠看出最後的結果6.00000000000000088817841970013E-1,略大於0.6,在Python中將其處理爲0.6000000000000001也就很天然了。

 

總結

經過這個例子咱們能夠看出,計算機表示數字具備自然的偏差,無論你採用多高的精度,多少個bit,最後至少都會產生一個的偏差。

相關文章
相關標籤/搜索