1. 程式人生 > 其它 >浮點數表示和運算

浮點數表示和運算

技術標籤:浮點數機器學習

浮點數的表示和運算

通過學習了計算機系統的相關知識,我對浮點數的表示和演算法部分格外關注,總結了一點知識點在這裡。

標題浮點數的表示

在現代計算機中,為了便於軟體移植,一般均採用 IEEE 754標準來表示浮點數。在介紹IEEE 754標準前,有必要先介紹一下浮 點數的表示形式。

既然尾數和階碼分別是定點小數和定點整數,即尾數和階碼都是有符號位的,那麼就可以寫出浮點數N的一般格式,如圖所示。
浮點數N的一般格式
從圖可知:
1)浮點數階碼的底r省略。

2)階符和階碼的位數k合起來反映浮點數的表示範圍及小數點的實際位置。

3)尾數M的位數n反映了浮點數的精度。

4)尾數的符號為m,它也是整個浮點數的符號位,表示了該浮點數的正負。

在大多數機器中,尾數為純小數,常用原碼或補碼錶示;階碼為定點整數,常用補碼或移碼錶示。

我們採用IEEE 754標準來表示浮點數的格式可以如以下圖:
在這裡插入圖片描述

按照IEEE 754標準,常用的浮點數有以下三種:
在這裡插入圖片描述
我們可以通過一個例題加深對其的理解:

[例1]若浮點數x的IEEE 754標準儲存格式為41360000H,試求其浮點數的十進位制數值。

解:將十六進位制數先展開為二二進位制,可得二進位制數的格式為

	0100 0001 0011 0110 0000 0000 0000 0000

	按照IEEE 754標準的格式排列一下:

	0 00000100000000000000

	指數e=階碼- 127=10000010-127=3

	包括隱藏位1的尾數1.M=1.011 0110 000 0000 0000 000=1.011011

	於是可得

x=(-1)sx1.Mx2e= +(1.011011)x23=+1011.011=(11.375)10

浮點數如何表示0:

用一種專門的位序列表示0。例如,IEEE 754單精度浮點數中,用“0000 000H"表示+0,用 “8000 00”表示-0。當運算結果出現階碼過小時,計算機將該數近似表示為0。

浮點數的階要用移碼錶示:

因為在浮點數的加減運算中,要進行對階操作,所以需要比較兩個階的大小。移碼錶示的實質就是把階加上一個偏置常數,使得所有數的階碼都是一-個正整數, 比較大小時,只要按高位到低位順序比較就行了,因而引入移碼可以簡化階的比較過程。

浮點數的加法和減法運算

我們可以知道,學習了浮點數的相關知識後,我們為了提高浮點數的精度,其尾數必須為規格化的數(因為規格化數精度最高),如果不是規格化數,則要通過修改階碼並同時左右移尾數的辦法使得其變成規格化數,而規格化的尾數必須滿足如下條件:

假設尾數為W,且基數為2,則當1>|w|≥1/2時,此浮點數為規格化數。一般來說,浮點數的尾數常用原碼和補碼來表示,因此要分兩種情況來分析:

1)當使用原碼錶示尾數時,要使得1>|w|≥1/2, 其尾數第一-位必須為 1,否則其絕對值一定小於1/2,故原碼錶示尾數規格化後的形式: 0.1xxX…或者 1.1Xxx…x.

2)當使用補碼錶示尾數時,要使得1>|w|≥1/2,當此浮點數為正數時,和原碼-一樣,最高位必須為1;當此浮點數為負數時,要使得1>|w|≥1/2,最高位必須為0,否則求反加1回到原碼時就會造成|w|<1/2,故補碼錶示尾數規格化後的形式: 0.1xxX…X或者1.0XXX<… (如果採用雙符號位表示,則是00.1XXX…X或者11.0XXX…X)。

注意兩個特殊的數:

1)當尾數為-1/2時,尾數的補碼為1.00…0.0 對於此數,它滿足1>|w|≥1/2,但是不滿足補碼的規格化形式,故規定-1/2不是規格化的數。

2)當尾數為-1時,尾數的補碼為1.00… 0,因為小數補碼允許表示-1,所以特別規定-1為規格化的數。

我們可以通過計算下面的問題,加深我們對其理解:

【例】100+10=?

(100)10=( 1100100)2 ,(10)10=(1010)2

1100100轉成浮點數是27 <00.1100100 (尾數採用 補碼錶示)

1010轉成浮點數是24 x 00.1010000(尾數採用補碼錶示)

千萬注意此處不能直接將尾數相加

浮點數的加/減運算也需要對階。現在的問題是高階向低階對齊,還是低階向高階對齊?如果是高階向低階對齊,那就需要左移,這樣就有可能改變符號位,肯定不行,因此對階一定是低階向高階對齊。繼續上面的例子,24 <00.1010000=27x00.0001010,這樣就可以直接將尾數相加了。這樣,兩步操作(對階、尾數求和)已完成。

尾數求和完成後,又會出現問題,求和後的尾數是規格化的嗎?若不是,還得把尾數規格化。如果尾數採用補碼錶示,則規格化的形式應該為00.1xXxX…X或者11.0xxx…x,需要分兩種情況分析:

1)當尾數求和後出現00.0xX<…X或者11.1xxX…x,如果不斷往右移動,則一直都會保持不變,因為補碼的算術右移是補符號位的;必須得左移,左移一位,階碼就減1。一直移到滿足補碼規格化的形式為止,至於要移動多少次是不確定的,以上步驟稱為左規。

2)當尾數求和後出現01.xxx… X或者10.xxx…x,我們可以想到變形補碼判斷溢位的方式,兩位符號位不同,表示溢位,可見尾數溢位了。但是,這在浮點數中不算溢位,可以通過右移來糾正。右移一位, 階碼加1。這種形式只要右移一次就可以變成規格化數,01.XXX… X右移一位變成00.1XX X…<; 10.xxx…右移一位變成11.0XXX…x ,以上步驟稱為右規。規格化問題解決了,浮點數的第3步操作(規格化)也就完成了。但是在對階和右移的過程中,很有可能會導致尾數的低位丟失,這樣就會引起誤差,影響精度。可以使用舍入法來提高尾數的精度,常用的舍入法有以下兩種:

1)“0舍1入”法。“0舍1入”法類似於十進位制中的“四捨五入”法,即在尾數右移時,被移去的末位為0,則捨去;被移去的末位為1,則在尾數的末位加1.但是這樣又很有可能導致尾數溢位,因此此時需要做一次右規,例如,011111 末尾加1,就變成0.0000,此時需要右規。

2)恆置“1”法。尾數右移時,不論丟掉的最高數值位是“1”或“0”,都使右移後的尾數末位恆置“1”。

對於浮點數的加/減運算,可以總結為以下4個步驟:

①對階,使兩數的小數點位置對齊。

②尾數求和,將對階後的兩尾數按定點加/減運算規則求和或者求差。

③規格化,為增加有效數字的位數,提高運算精度,必須將求和或求差後的尾數規格化

④舍入,為提高精度,要考慮尾數右移時丟失的數值位。

當然,以上4個步驟完成後,還需要加上一步,即檢查一下 最後的結果是否溢位,由於浮點數的溢位完全是用階碼來判斷的,假設階碼採用補碼來表示,溢位就可以使用雙符號位判斷溢位的方式來判斷此浮點數是否溢位,過程如下:

			if (階符= =01)
						
				上溢,需做中斷處理;
						
			else if (階符= =10)
						
				下溢,按機器零處理;
						
			else :
						
				結果正確;

理論知識可能不是很懂,我們下面來看個題就會容易理解一點的

【例】已知十進位制數 x= -5/256, y=+59/1024, 按機器補碼浮點數運算規則計算x-y,結果用二進位制表示。其中,浮點數格式如下:數的階符取兩位,階碼取3位,數符取兩位,尾數取9位(舍入時採用0舍1入法)。

解:首先將x和y轉換成浮點數,如下:

x=-5/256=2-101x(11.101000000)

y= 59/1024 =2-100x(00.111011000)

由於jx=11101,因此[jx]補=11011,同理[-jy]補+ =00100.

所以:
[x]補=11011,11.011000000

[y]補=11100,00.111011000

下面可以按照浮點數加/減運算的5個步驟來做:

1)對階。求階差: [△j]補=[jx]補-[jy]補=[jx]補+[-jy]補

=11011+00100

=111111 (補碼全1表示-1)

因此,x的階碼要低1,故應該x向y對齊,x尾數需要右移一位,階碼加1,如下:

[x]補=11100,11.101100000

2)尾數求差。

 11.101100000

+11.000101000 (這裡加的是y尾數的負數補碼)

 =10.110001000

即[x-y]補=11100,10.110001000
3)規格化。尾數出現10.XXx…x形式,說明需要右規一次即可, 階碼加1,最後可得

[x-y]補=11101,11.010001000 (加了下劃線的0為右規丟棄的0)

4)舍入處理。由於右規低位丟0,因此直接捨去。

5)溢位判斷。最後階符為11,沒有溢位,應將[x-y]補=11101,11.011000100轉換為真值。階碼為11101,換成原碼為11011,說明真實值為-3;同理,尾數為-0.1001111故最後的結果為2-3x(-0.1001111)。

進一步,在C語言程式中,為什麼關係表示式“123456789= =(int)(float)123456789”的結果為“假”,而關係表示式“123456= =(int)(loat)123456”和“123456789==(int)(double)123456789”的結果都為“真”?

首先應該明白,在C語言中,float 型別對應IEEE 754單精度浮點數格式,即float型資料的有效位數只有24位(相當於有7位十進位制有效數); double 型別對應IEEE 754雙精度浮點數格式,有效位數有53位(相當於有17位十進位制有效數); int 型別為32位整數,有31位有效位數(最大數為231-1=2147483647)。

整數123456789的有效位數為9位,轉換為float型資料後肯定發生了有效位數丟失,再轉換成int型資料時,已經不是123456789了。所以,關係表示式“123456789= =(int)(float)123456789”的結果為“假”。

整數改為123456後,有效位數只有6位,轉換為float型資料後有效位數沒有丟失,因而數值沒變,再轉換為int型資料時,還是123456。所以,關係表示式“123456= =(int)(float)123456”的結果為“真”。

整數123456789的有效位數為9位,轉換為double型資料後,不會發生有效位數丟失,再轉換成int 型資料時,還是123456789。所以,關係表示式“123456789= =(int)(double)123456789”的結果為“真”。