題目來源:計算機系統第三次小班討論課選題二。
題目描述:說明浮點數加法操作的原理,並編寫代碼,在二進制與彙編這一級別進行分析。
一、 浮點數存儲原理
如二進制1.0110100111,我們肯定很希望在計算機中有足夠的空間,分別存儲二進制浮點數的各位與小數點。但由於小數點位置的不確定性,直觀的存儲方式並不美觀,我們採用如下方法存儲二進制浮點數:
除0以外的任何二進制浮點數均可以表示成如下形式:
如10.110100111,可以表示爲1.0110100111×(10)^(10),10爲十進制數字2的二進制表示,即:
這一操作稱爲浮點數的規格化表示。
我們可以看到,對於除0以外的任一浮點數,均可以由±(符號)、f、E唯一確定,因此IEEE754標準作出瞭如下規定:
浮點數由“符號”、“階碼”和“尾數”3部分構成。
對於32位系統,最高位作爲符號位(0代表正,1代表負),之後8位用於存儲階碼E,低32位存儲尾數。
二、 浮點數加法原理
浮點數的規格化與存儲方式決定了浮點數相加與非符號數相加不同。
目前浮點加法算法主要有基本算法、Two-Path算法和Triple-data-path算法,
在這裏只考慮同符號的浮點數加法,介紹一種基本算法:
浮點數的加法運算可分3步:
第1步:在尾數運算前完成對階工作。
第2步:對尾數進行加法運算,並處理進位。
第3步:對運算結果格式化,還原爲IEEE浮點格式。
具體操作步驟爲:
(1) 對階操作,即比較兩個浮點數的階碼值的大小.求△E=Ex-Ey。
當其不等於零時,首先應使兩個數取相同的階碼值。
實現方法是,將原來階碼小的數的尾數右移|△E|位,其階碼值加上|△E|, 該浮點數的值不變,精度變差。
尾數右移時, 符號位不參加移位,尾數高位補0。
(2) 實現尾數的加(減)運算,對兩個完成對階後的浮點數執行求和(差)操作。
(3) 規格化處理,若得到的結果不滿足規格化規則,就必須把它變成規格化的數。
若尾數運算結果溢出。此時應使結果尾數右移一位,並使階碼的值加1。
(4) 舍入操作。在執行對階或右規操作時,會使尾數低位上的多位的數值被移掉,使數值的精度受到影響。
常用的辦法有“0”舍“1”入法,即移掉的最高位爲1時,則在尾數末位加1;爲0時則捨去移掉的數值。
(5) 判結果的正確性,即檢查階碼是否溢出。浮點數的溢出是以其階碼溢出表現出來的。
三、浮點數加法的具體實現
#include <stdio.h>
int main() {
unsigned a1, a2;
unsigned flag = 0;
scanf("%x%x",&a1,&a2);
unsigned newe=0,newt=0;
if (a1 == 0) {
printf("result:%x\n",a2);
return 0 ;
}
if(a2 == 0) {
printf("result:%x\n",a1);
return 0;
}
unsigned temp = 0x7f800000;
if(a1 >= temp || a2 >= temp) {
printf("result:Not a number\n");
return 0;
}
unsigned e1 = (a1 & temp) >> 23,e2 = (a2 & temp) >> 23;
unsigned d = 0;
if(e1 == e2) {
flag=1;
} else if(e1 < e2) {
unsigned etemp=e1;
e1=e2;
e2=etemp;
unsigned atemp=a1;
a1=a2;
a2=atemp;
}
newe=e1;
d=e1-e2;
unsigned t1 = a1 & 0x7fffff, t2 = a2 & 0x7fffff;
if(flag!=1)
t2=t2|0x800000;
t2 = t2 >> d;
if(flag==1) {
newt = t1+t2+0x800000+0x800000;
} else {
newt=t1+t2+0x800000;
}
if(newt>0xffffff) {
newt >>= 1;
newe++;
}
newt=newt & 0x7fffff;
unsigned sign=0x80000000&a1;
if(newe>0xff)
printf("result:Not a number\n");
unsigned result=sign + (newe <<23) + (newt);
printf("result:%x\n",result);
return 0;
}
其中a1,a2爲加數、被加數對應的無符號數類型。
爲直觀、本質地理解浮點數加法原理,本程序僅針對無符號數進行運算處理。
如計算1.23+11,需要輸入:“3f9d70a4 41300000”,分別爲1.23與11對應的16進制無符號數。
程序輸出:“4143ae14”,爲12.23對應的16進制無符號數,輸出結果正確。
測試用例1:
輸入:3f9d70a4 41300000
輸出:4143ae14
說明:1.23+11=12.23
測試用例2:
輸入:3de76c8b 4340199a
輸出:43403687
說明:0.113+192.1=192.213