天天看點

定點除法運算

計算機中,除法運算和乘法運算一樣,是非常常用的一種運算。同樣,除法運算在計算機中的實作也分為符号部分和數值部分兩部分。

(1)符号位。符号位的确定和乘法運算的規則一緻,除法運算的符号位無法通過轉換補碼,加入到除法運算中,必須單獨進行處理。根據除法運算的規則:被除數和除數之間,符号位相同則為正,符号位不同則為負。設被除數和除數分别為X和Y,Xf和Yf分别代表X和Y的符号位,除法運算結果為Z,Zf代表Z的符号位。如下表所示。

除法運算符号位結果真值表

Xf Yf Zf
1 1
1 1
1 1

根據真值表,可得除法運算符号位的邏輯表達式為:

Zf=Xf異或Yf

(2)恢複餘數法實作數值部分除法。數值部分除法在計算機中的實作也是從除法運算的筆算演變過來的。我們不考慮符号位,以兩個正數的除法為例,做出一個除法運算筆算例子的完整過程。

【例】設二進制小數X=0.1001,Y=0.1101,計算X/Y

X/Y的豎式如下:

                                     0.  1  0  1  1

0.1101          /  __________________

                    0.  1  0  0  1  0

                    0.  0  1  1  0  1

—————————————————

                    0.  0  0  1  0  1  0  0

                    0.  0  0  0  1  1  0  1

—————————————————

                    0.  0  0  0  0  1  1  1  0

                    0.  0  0  0  0  1  1  0  1

—————————————————

                    0.  0  0  0  0  0  0  0  1

結果為:X/Y的商為0.1011,餘數為0.00000001

計算機中的定點數的除法運算,商的位數一般與被除數和除數的位數相等。觀察運算過程發現,除法運算筆算每次都上商,都是通過心算比較餘數和除數的大小關系,如果餘數大于除數,上1,然後做減法得出新的餘數,新的餘數低位補0;如果餘數小于除數,則上0,餘數低位補0得出新的餘數。

是以,除法運算的筆算每次上商是1還是0,關鍵是看餘數和除數之間的大小關系比較。筆算中我們都是通過心算進行大小比較,但是,機器沒有所謂“心算”,隻能在餘數和除數之間做減法操作,檢視結果正負來判斷大小關系。如果餘數減去除數的結果為正,說明應該上商為1,而将減法的結果低位補0,就得到新的餘數;而如果餘數減去除數的結果為負,說明應該上商0,減法的結果無意義,恢複餘數法的做法是,将減法結果加上除數,還原減法操作前的餘數,然後再将餘數低位補0,得到新的餘數。

從上面除法運算筆算 例子的豎式中可以看出,餘數和除數之間的減法操作,在計算機中實際上使用的是加法器,将減法轉換為補碼加運算的方法實作的。設餘數為A,除數為B,則:

[A-B]補=[A+(-B)]補=[A]補+[-B]補

觀察筆算除法豎式發現,每次上商後,除數都需要右移一位來與新的餘數對齊,機器字長為5的除法運算需要加法器的位數至少為9,。計算機中,我們可以對筆算算法稍作改變,除數右移一位的操作可以用餘數左移一位來代替。這樣就不需要在餘數和新除數前加連續的0.但左移後的餘數已經不是真正的餘數,隻有再将餘數重新右移才能得到真正的餘數。

筆算求商時,商的結果是從高位到低位逐位算出來的。在計算機的實作中,計算出每一位的商以後,并不是直接把結果寫到寄存器相應的位中,而是從高位開始,将每一位的商寫到寄存器的最低位,然後左移一位,等待下一位商寫到寄存器的最低位,再左移,再求下一位商……如此循環直到最低位寫到寄存器中。

此外,定點小數的除法,如果被除數的絕對值大于或等于除數的絕對值,那麼很明顯,除法結果的絕對值會大于或等于1,即商成為一個非純小數。無法再用定點小數表示。并且,除法運算應該避免被除數和除數為0.是以,設被除數為X,除數為Y,X*和Y*分别為X和Y的絕對值。定點小數的除法必須滿足下面的條件:

0<|被除數|<|除數|

【例】設二進制純小數X=-0.1001,Y=0.1101,請使用恢複餘數法,計算并列出執行X/Y的操作過程。

求X和Y的原碼,得

[X]原=1.1001,[Y]原=0.1101

首先判斷符号位:

Zf=Xf異或Yf=1異或0=1

求x和y的絕對值,得

X*=0.1001,Y*=0.1101

求X*和Y*的原碼,得

[X*]原=0.1001,[Y*]原=0.1101

求X*、Y*和-Y*的補碼,得

[X*]補=0.1001,[Y*]補=0.1101,[-Y*]補=1.0011

餘數恢複法執行過程如下:

①餘數R=X*.商為0.0000.

②[R]補=[R-Y*]補=[R]補+[-Y*]補=0.1001+1.0011=1.1100,結果為負數。

③商的末尾置0,為0.0000,左移一位,還是0.0000;餘數還原:[R]補+[Y*]補=1.1100+0.1101=0.1001;餘數左移一位,末位補0,得[R]補=1.0010.

④[R]補=[R-Y*]補=[R]補+[-Y*]補=1.0010+1.0011=0.0101,結果為正數。

⑤商的末位置1,為0.0001,左移一位,得商為0.0010;餘數左移一位,末位補零,得[R]補=0.1010

⑥[R]補=[R-Y*]補=[R]補+[-Y*]補=0.1010+1.0011=1.1101,結果為負數。

⑦商的末尾置0,為0.0010,左移一位,得商為0.0100;餘數還原:[R]補=[R]補+[Y*]補=1.1101+0.1101=0.1010;餘數左移一位,末位補零,得[R]補=1.0100

⑧[R]補=[R-Y*]補=[R]補+[-Y*]補=1.0100+1.0011=0.0111,結果為正數。

⑨商的末尾置1,為0.0101,左移一位,得商為0.1010;餘數左移一位,末尾補零,得[R]補=0.1110

⑩[R]補=[R-Y*]補=[R]補+[-Y*]補=0.1110+1.0011=0.0001,結果為正數。

①①商的末位置1,為0.1011.

數值運算結果和符号結果結合,得[X/Y]原=1.1011

總結:首先根據計算位數設商為0.0000(本題的小數點後的精度為4,超出的均為溢出丢棄),然後根據[R]補=[R-Y*]補=[R]補+[-Y*]補的運算結果正負,來确定商的末尾置0還是置1(負數置0,正數置1),并且在每次計算後,計算結果都要左移一位,末尾補零,得到新的餘數,然後再用這個新的餘數進行計算(同樣的公式)。記得這一點差别,商的末位無論置0還是置1,也需要左移,但是在下一步進行置0或是置1是在未移動的結果上進行置0或置1(不能用移動後的商)。同時,如果餘數計算的結果為負,那就要恢複餘數,也就是用餘數再加上除數,然後再進行下面的操作。對于循環幾次,取決于除數的位數,本題中除數小數點位數為四位,是以要移動四次,得到最後的結果便是結果(這時無符号位),最後我們再加上一開始判斷的符号位便是最終結果。

(3)加減交替法實作數值部分除法。加減交替法也稱不恢複餘數法,是對恢複餘數法的一種改進算法。恢複算法每次用餘數減去除數,都是為了觀察餘數和除數的大小關系,如果減法結果為負數,說明餘數小于除數,那麼就必須将結果再加除數來還原餘數。反複的加減操作很大程度上影響了恢複餘數法的運算效率。

再次分析原碼恢複餘數法發現,餘數減去除數,設結果為r:

如果R>0,上商1,R 左移一位,低位補0,就得到新的餘數。下一步新的餘數再減除數,确定下一位商的結果。也就是說,如果R>0,确定下一位的商和r值的運算為:

R=2R-Y*

如果R<0,上商0,然後需要恢複餘數,即R+Y*,将R+Y*的結果再左移一位,低位補0,就得到新的餘數。下一步新的餘數再減去除數,确定下一位商的結果。也就是說,如果R<0,确定了下一位商和R值的運算為:

R=2(R+Y*)-Y*                即R=2R+Y*

如此一來,當每次餘數減除數的結果R為正或者負時,我們隻需要根據正負上商,并按照不同公式計算新R的值來确定下一位商即可。不需要在進行當R為負數時恢複餘數這樣繁瑣的操作了。

【例】設二進制純小數X=-0.1001,Y=0.1101,請使用加減交替法,計算并列出執行X/Y的操作過程。

求X和Y的原碼,得

[X]原=1.1001,[Y]原=0.1101

首先判斷符号位:

Zf=Xf異或Yf=1異或0=1

求X和Y的絕對值,得X*=0.1001,Y*=0.1101

求X*和Y*的原碼,得

[X*]原=0.1001,[Y*]原=0.1101

求X*、Y*、-Y*的補碼,得

[X*]補=0.1001,[Y*]補=0.1101,[-Y*]補=1.0011

加減交替法的執行過程如下:

①設餘數R=X*=0.1001,商為0.0000.

②[R]補=[R-Y*]補=[R]補+[-Y*]補=0.1001+1.0011=1.1100,結果為負數。

③商的末位置0,為0.0000,左移一位,還是0.0000

④[R]補=[2R+Y*]補=2[R]補+[Y*]補=1.1000+0.1101=0.0101,結果為正數。

⑤商的末位置1,為0.0001,左移一位,得商為0.0010。

⑥[R]補=[2R-Y*]補=2[R]補+[-Y*]補=0.1010+1.0011=1.1101,結果為負數。

⑦商的末位置0,為0.0010,左移一位,得商為0.0100.

⑧[R]補=[2R+Y*]補=[2R]補+[Y*]補=1.1010+0.1101=0.0111,結果為正數。

⑨商的末位置1,為0.101,左移一位,得商為0.1010.

⑩[R]補=[2R-Y*]補=[2R]補+[-Y*]補=0.1110+1.0011=0.0001,結果為正數。

①①商的末位置1,得商為0.1011

數值運算結果和符号結果結合,得[X/Y]原=1.1011

總結:加減交替法采用了公式計算,前面和不恢複餘數法一樣,計算符号位,設餘數為被除數,商為0,[R]補=[R-Y*]補=[R]補+[-Y*]補計算,而下面需要根據結果的正負來使用公式,如果結果為負數,則用R=2R+Y*計算出餘數,然後再進行判斷。如果結果為正數,則用R=2R-Y*計算,然後判斷正負。循環的次數和不恢複餘數法一樣,由除數決定。最後循環結束再結合符号位就是最終的結果。

浮點數的加減運算

浮點數與定點數相比,所表示的範圍更寬,有效精度更高,更加适合于科學計算。但浮點數的格式比定點數要複雜,硬體電路更複雜,實作的成本更高。一些微處理器自身不帶有浮點運算功能,但另外配有協處理器,專門用于浮點數的四則運算。

我們在前面讨論了浮點數在機器中的表示方法。階碼E采用補碼或移碼的方式表示;尾數F采用原碼或補碼方式表示。設有兩浮點數X和Y進行加減運算時,必須按以下幾步執行。

1.對階

使X和Y的小數點位置對齊。才可以進行加減操作。

由于階碼不同,X和Y的尾數的對應位所代表的權值是不同的。加減操作前,必須将X和Y的小數點位置對齊,也就是使X和Y的價碼相等。對階的原則是階碼小的數進行調整,打破浮點數規格化的要求,使兩個數的價碼相等。例如:

設二進制浮點數X=101.1和Y=1.011,如果要執行X+Y。首先看X和Y在計算機中用N=2^E*F的形式表示,使用規格化形式,為:

X=2^3  *  0.101100

Y=2^1  *  0.101100

X和Y的價碼分别為3和1,尾數不能直接相加。按照階碼小的數向階碼大的數對齊原則,調整後的Y的表示為:

Y=2^3  *  0.001011

2.尾數加減

将對階後的兩尾數按定點加減運算規則進行操作,尾數的加減運算一般使用變形補碼的加減運算方式來實作。

繼續上面的例子,X和Y對階完成後,尾數就可以進行加運算:

[0.101100]補`=00.101100

[0.001011]補`=00.001011

[0.101100+0.001011]補`=[0.101100]補+[0.001011]補`=00.101100+00.001011=00.110111

3.規格化

為增加有效數字的位數,提高運算精度,必須将求和(差)後的位數規格化。規格化又分為左規和右規兩種:

(1)左規。當尾數的變形補碼加減運算結果出現00.0***或11.1*****時,說明加減操作無溢出,并且,最高數值位表明,尾數不符合規格化要求,需左規。左規時尾數左移一位,階碼減一,直到符合補碼規格化表達式為止,即結果為00.1********或11.0****

(2)右規。當尾數出現01.********或10.**********時,表示尾數的變形補碼加減運算結果溢出。在這定點加減運算中是不允許的,但在浮點運算中這不算溢出,可通過右規處理後繼續使用。右規時尾數右移一位,階碼加一。

繼續上面的例子,執行完尾數加減操作後,X+Y的結果為:

Z=2^3*0.110111

結果符合規格化要求,是以X+Y的結果即為上式。用實數方式表示為:X+Y=(110.111)2進制

【例】兩浮點數X=2^+010   *  0.110100,Y=2^+100  *  (-0.101010),求X+Y

階碼取三位,尾數取6位(均不包括符号位),設階碼和尾數均采用補碼表示方式,機器表示的形式分别為:

[X]補=0010 0110100

[Y]補=0100 1010110

第一步,對階:先求階差(兩階碼的補碼相減),減去正數補碼0100就是加負數補碼1100,使用變形補碼方式執行:

00 010+11 100=11 110

結果的真值為-2,即X的階碼比Y的階碼小2.[X]補的階碼增大成0100,尾數右移兩位,即

[X]補=0100 0001101

第二步:尾數以變形補碼的形式相加:

00.001101+11.010110=11.100011

相加結果為:0100 1100011

第三步:規格化:

最高有效位與符号位相同,需要左規,尾數左移一位,階碼減1,結果為:

[X+Y]補=0011 1000110,即

X+Y=2^+011  *  (-0.111010)             【補碼的補碼即為原碼】

4.舍入

在對階和右規的過程中,可能會将尾數的低位丢失,引起誤差,影響了精度,為此可以用舍入法來提高尾數的精度。常用的舍入法有三種:截去法、“恒置1”法和“0舍1入”法。

截去法最簡單,不用考慮 右移操作導緻丢失的資料,直接丢棄。

“恒置1”法也不考慮右移操作導緻被丢掉的資料,而是直接将右移操作後的末尾恒置"1".從統計學角度看,“恒置1”法的平均誤差為0,與截去法相比,有更高的可能性使結果更加準确。

“0舍1入”法類似于十進制運算中的“四舍五入”法,即在尾數右移時,如果被移去的數值的最高位為0,則直接舍去;如果被移去的數值最高位為1,則在新尾數的末位加1.這種方法可以保證最大誤差是最低誤差上的-1/2到1/2之間,正誤差可以和負誤差抵消。是比較理想的方法,但實作起來比較複雜。并且有可能使尾數又溢出,如果溢出則再做一次右規。

【例】兩浮點數X=2^+10  *  0.1101,Y=2^+01  *  0.1011,求X+Y,舍入用“0舍1入法”。

階碼取三位,尾數取四位(均不包括符号位),設階碼和尾數均采用補碼表示方式,機器表示的形式分别為:

[X]補=0010 01101

[Y]補=0001 01011

第一步,對階,我們換一種方式,通過觀察,我們發現Y的階碼比X的階碼小1,是以把Y的階碼程式設計0010,需要尾數右移,即01011右移一位,為00101,題目要求用0舍1入法,我們舍去的為1,是以尾數要加1,是以最終的位數為00110.[Y]補=0010 00110

第二步,尾數以變形補碼形式相加

00.1101+00.0110=01.0011

第三步,規格化

因位數符号位為01,需要右規(尾數右移一位,階碼加1),右移後的位數結果為:01001.根據“0舍1入”法可知,尾數被移去一位,該位為1,是以尾數右移一位後末位要加1,即01010,得

[X+Y]補=0011 01010

浮點數的乘法和除法運算

按照數學運算公式,我們知道,兩個浮點數相乘,乘積的階碼等于兩個乘數的階碼之和,乘積的尾數等于兩個乘數的尾數的相乘;兩個浮點數相除,商的階碼等于被除數的階碼減去除數的階碼,商的尾數等于被除數的尾數除以除數的尾數。設浮點數X和Y分别為:

X=2^EX  *  Fx

Y=2^EX  *  Fy

X  *  Y=2^(EX+EY)  *  (Fx  *  Fy)

X  /  Y=2^(EX-EY)  *  (Fx/Fy)