版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mr0cheng/article/details/83187166
加法部分代码:
#include "stdio.h"
#include "project06.support.h"
struct node
{
unsigned long long int sign;
unsigned long long int exp;
unsigned long long int frac;
unsigned long long int sig;
};
double add(double a, double b)
{
struct node nodea, nodeb;
union double_precision dpa;
union double_precision dpb;
dpa.drep = a;
dpb.drep = b;
//得到符号位
nodea.sign = ((dpa.irep >> 63) & 0x1);
nodeb.sign = ((dpb.irep >> 63) & 0x1);
//得到指数
nodea.exp = ((dpa.irep >> 52) & 0x7ff);
nodeb.exp = ((dpb.irep >> 52) & 0x7ff);
//得到小数
nodea.frac = (dpa.irep & 0x000fffffffffffff);
nodeb.frac = (dpb.irep & 0x000fffffffffffff);
//得到有效数
nodea.sig = ((dpa.irep & 0x000fffffffffffff) | 0x0010000000000000);
nodeb.sig = ((dpb.irep & 0x000fffffffffffff) | 0x0010000000000000);
//判断a是否为NAN 或者 INFINITY
if (nodea.exp == (unsigned long long int)0x7ff)
{
if (nodea.frac != (unsigned long long int)0)
{
return NAN;
}
else
{
return INFINITY;
}
}
//判断b是否为NAN 或者 INFINITY
if (nodeb.exp == (unsigned long long int)0x7ff)
{
if (nodeb.frac != (unsigned long long int)0)
{
return NAN;
}
else
{
return INFINITY;
}
}
struct node node_res;
long long int siga, sigb, sig_res;
//将有效小数变成有符号数,方便将减法运算变成加法运算
siga = (long long int)nodea.sig;
sigb = (long long int)nodeb.sig;
if (nodea.sign == 1)
{
siga *= -1;
}
if (nodeb.sign == 1)
{
sigb *= -1;
}
//指数小的进行右移
if (nodea.exp > nodeb.exp)
{
sig_res = siga + (sigb >> (nodea.exp - nodeb.exp));
node_res.exp = nodea.exp;
}
else
{
sig_res = (siga >> (nodeb.exp - nodea.exp)) + sigb;
node_res.exp = nodeb.exp;
}
//判断结果是否为0
if (sig_res == 0)
return 0;
//将带符号的有效小数转成不带符号的
node_res.sign = 0;
if (sig_res < 0)
{
sig_res *= -1;
node_res.sign = 1;
}
unsigned long long int temp = (unsigned long long int)sig_res;
//判断是否溢出,如果溢出则右移
if ((temp & 0x0020000000000000) == 0x0020000000000000)
{
temp = temp >> 1;
node_res.exp += 1;
node_res.frac = (temp & 0x000fffffffffffff);
node_res.sig = ((temp & 0x000fffffffffffff) | 0x0010000000000000);
}
//循环左移
while ((temp & 0x0010000000000000) != 0x0010000000000000)
{
temp = temp << 1;
node_res.exp -= 1;
}
//pack
node_res.sig = temp;
node_res.frac = (temp & 0x000fffffffffffff);
union double_precision dp_res;
dp_res.irep = (node_res.sign << 63) + (node_res.exp << 52) + node_res.frac;
//日志
printf("value a: %f\n", a);
printf("value b: %f\n", b);
printf("sign= %016llx exp= %016llx frac= %016llx sig= %016llx \n", nodea.sign, nodea.exp, nodea.frac, nodea.sig);
printf("sign= %016llx exp= %016llx frac= %016llx sig= %016llx \n", nodeb.sign, nodeb.exp, nodeb.frac, nodeb.sig);
printf("sign= %016llx exp= %016llx frac= %016llx sig= %016llx \n", node_res.sign, node_res.exp, node_res.frac, node_res.sig);
printf("result = %lf\n\n", dp_res.drep);
return dp_res.drep;
}
验算部分代码:
#include "stdio.h"
#include "project06.support.h"
int main(){
double a = 8.75;
double b = 0.5;
add(a,b);
/*
example 10.
+8.75 (4021800000000000)
sign bit: 0
biased exponent: 402
fraction:
1800000000000
significand: 11800000000000
+0.50 (3fe0000000000000)
sign bit: 0
biased exponent: 3fe
fraction:
0000000000000
significand: 10000000000000
9.25
*/
a = 6.25;
b = 4.75;
add(a,b);
/*
example 11.
+6.25 (4019000000000000)
sign bit: 0
biased exponent: 401
fraction:
9000000000000
significand: 19000000000000
+4.75 (4013000000000000)
sign bit: 0
biased exponent: 401
fraction:
3000000000000
significand: 13000000000000
+11.00
*/
a = -8.75;
b = 0.5;
add(a,b);
/*
example 12.
-8.75 (c021800000000000)
sign bit: 1
biased exponent: 402
fraction: 1800000000000
significand: 11800000000000
+0.50 (3fe0000000000000)
sign bit: 0
biased exponent: 3fe
fraction: 0000000000000
significand: 10000000000000
-8.25
*/
return 0;
}