题目来源:计算机系统第三次小班讨论课选题二。
题目描述:说明浮点数加法操作的原理,并编写代码,在二进制与汇编这一级别进行分析。
一、 浮点数存储原理
如二进制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