理论分析:
双精度浮点数(double)是计算机使用的一种数据类型,使用 64 位(8字节) 来存储一个浮点数。双精度型占8 个字节内存空间,其数值范围为-1.7E308~+1.7E308。在IEEE754标准下,第一位为符号位,其后11位为阶码位,最后52位为小数位。每一位上均为0/1,为二进制形式表达。
由于在计算机中,数据的运算是通过二进制这一工具,双精度浮点数的运算同样遵循二进制计算的进位、记值原则。
根据题意,double类型数据是否满足加法交换律可以通过对a+b,b+a分别求值比较二者的二进制表达是否相同来判断;同理可知,加法结合律可以通过对(a+b)+c和(b+c)+a分别求值,比较二者二进制表达是否相同。如进行大量运算后所得二进制表达相同,则遵循此规律;反之则不错遵循此运算规律。
算法设计:
为了实现以上运算过程,程序需要实现以下几个基本方面
1.
将输入端输入的十进制double类型小数转化成64位二进制double类型小数
2.
能够实现64位二进制小数的加法运算,得到两者和的二进制表达
对于加法运算过程,还需要实现以下几步
(1) 对阶操作,即比较两个浮点数的阶码值的大小
(2) 尾数相加,实现尾数的加法运算,对两个完成对阶后的浮点数执行求和操作
(3) 规格化处理
3.
可判断两个64位二进制小数是否相同(此过程也可以通过在输出端直接输出两个小数进行比对,如此可以更直观地表示)
编程实现:
1.
将十进制double类型小数k转化成64位二进制double类型小数
scanf("%lf",&k);
p=(double*)&n;
*p =k;
for(i= 0;i<64;i++)
{ if(n&bbb)
a[i]= 1;
else
a[i]= 0;
bbb=bbb<<1;
}
将转化成的64位二进制小数储存在数组a[i]中
2.
进行64位二进制小数的加法运算,得到两者和的二进制表达
(1)对阶操作:
int i;
for(i=1;i<12;i++)
{
if(a[i])
ea+= pow(2,12-i);
}
for(i=0;i<12;i++)
{
if(b[i])
eb+=pow (2,12-i);
}
e=ea-eb;
for(i=9;i<63;i++)
{
a[i+1]=a[i];
}
for(i=9;i<63;i++)
{
b[i+1]=b[i];
}
(2)对阶完成后,进行尾数的二进制加法
int d[65]={0};
for(i=63;i>12;i–) d[i+1]=a[i]+b[i];
for(i=64;i>=12;i–){ ——进行进位运算
if(d[i]==2){
d[i]=0;
d[i-1]++;
}
if(d[i]==3){
d[i]=1;
d[i-1]++;
}
}
(3)规格化处理
若得到的结果不满足规格化规则,就必须把它变成规格化的数,对双符号位的补码尾数来说,就必须是001××…×或110××…×的形式。这里的规格化处理规则是:
当结果尾数的两个符号位的值不同时,表明尾数运算结果溢出。此时应使结果尾数右移一位,并使阶码的值加1
当尾数的运算结果不溢出,但最高数值位与符号位同值,表明不满足规格化规则,此时应重复地使尾数左移、阶减减1,直到出现在最高数值位上的值与符号位的值不同为止
for(i=1;i<12;i++)
{
if(a[i])
e+= pow(2,12-i);
}
if(a==1) e=e+1;
for(j=0;j<52;j++)
printf("%d",sum[j]);
printf("%d",e);
(4) 舍入操作
在执行对阶或右规操作时,会使尾数低位上的一位数值被移掉,使数值的精度受到影响,可以把移掉的几个高位的值保存起来供舍入。
保存最高位:
int i,m,n;
m=a[63];
n=b[63];
在加法运算后补上最高位
int f[65],g[65];
for(i=0;i<64;i++)
{
f[i]=a[i];
}
f[64]=m;
for(i=0;i<64;i++)
{
g[i]=b[i];
}
g[64]=n;
(5) 判结果的正确性
测试分析:
进行交换律验证,随机输入数据a=3.697,b=1.238,得到二者加和二进制表达
改变输入顺序,得到b+a的二进制表达
可见浮点数加法符合交换律
同理进行结合律验证,随机输入一组数据a=3.261,b=2.365,c=1.987,运算后得到(a+b)+c的二进制表达,输出数据如下
更改数据输入顺序,计算(b+c)+a的二进制表达,如初数据如下
继续使用多组数据进行验证,所得皆不符合结合率
结论:
双精度浮点数的加法符合交换律,不符合结合律。
原因是因为对阶操作时舍去了高位的一位或者几位的0、1,在舍入操作后还有可能导致溢出,导致进行结合律运算时会出现偏差。