您的位置:首页 > 其它

浮点转定点算法-加法运算

2014-04-28 16:44 281 查看
这里默认用的是32位的float存储,其具体规则可以看个连接http://bbs.chinaunix.net/thread-3746530-1-1.html

将浮点数用32位的定点形式表示。

将两个数通过移位扩大至相同的倍数。

定点加法运算。

将上一步的运算结果还原为浮点表示。
#define MIN(X,Y) (X>=Y?Y:X)

/** 浮点的加法运算转换为定点的加法运算
*  author : zgr 2014-04-03
* 1. 内存中符号位+阶码+尾数的浮点表示法转换为符号位+整数部分+尾数部分的表示法
* 2. 找到合适的Q值,并取较大的Q值,然后通过移位操作转为同一Q值的定标数
* 3. 做定标数的加减运算
* 4. 将定标数的结果根据其Q值,转换为float的表示形式(符号位+阶码+尾数)
*/
float inter_fadd(float x1, float x2){
int Q1, Q2, Q;
int xq1, xq2, xq;
int ipart, exponent1, exponent2, n, index;
int effective1, effective2;

if(((*(int*)&x1)&0x7f800000)==0x00000000){ //阶码为0,以0计
effective1 = 0;
ipart = 0;
exponent1 = 30;
} else if(((*(int*)&x1)&0x7f800000)==0x7f800000){ //放弃非法数值或者无穷大或无穷小的数值
return 0.0f;
} else {
effective1 = ipart = (((*(int*)&x1)&0x7fffff) | 0x800000); //取出有效数字部分 1.XXXXXXXXXXX
exponent1 = 150 - ((*(int*)&x1)>>23 & 0xff); //23 - (b-127)
//通过移位截断小数部分,保留整数部分
if(exponent1 < 0)
ipart = ipart << (-exponent1);
else if(exponent1>31)
ipart = ipart >> 31;
else
ipart = ipart >> exponent1;
}

//计算合适的Q值,这里取最长30位存放有效数字,做到最大的精确度,而不溢出
for(n=0; n<31; n++){
if(ipart < (1<<n)){
Q1 = 30 - n;
break;
}
}

if(((*(int*)&x2)&0x7f800000)==0x00000000){
effective2 = 0;
ipart = 0;
exponent2 = 30;
} else if(((*(int*)&x2)&0x7f800000)==0x7f800000){
return 0.0f;
} else {
effective2 = ipart = (((*(int*)&x2)&0x7fffff) | 0x800000);
exponent2 = 150 - ((*(int*)&x2)>>23 & 0xff);
if(exponent2 < 0)
ipart = ipart << (-exponent2);
else if(exponent2>31)
ipart = ipart >> 31;
else
ipart = ipart >> exponent2;
}

for(n=0; n<31; n++){
if(ipart < (1<<n)){
Q2 = 30 - n;
break;
}
}

//取较小Q值,保证不溢出
Q = MIN(Q1, Q2);
//通过移位,扩展至同样的倍数
if(exponent1>=0 && (exponent1-Q)>=0){
xq1 = effective1>>(exponent1-Q);
}else{
xq1 = effective1<<(Q-exponent1);
}
if(exponent2>=0 && (exponent2-Q)>=0){
xq2 = effective2>>(exponent2-Q);
}else{
xq2 = effective2<<(Q-exponent2);
}
//定标运算
xq = xq1 + xq2;

//找到最高有效位的索引,用于浮点存储
n = -1;
for(index=0; index<31; index++){
if(xq & (1<<index)){
n = index;
}
}
if(n == -1) //全为0,则为0.0f
return 0.0f;
else{
exponent1 = (n-Q) + 127; //计算阶码
//保留23位尾数
if(n-23>=0){
xq = xq>>(n-23);
}else{
xq = xq<<(23-n);
}
//保留符号位,拼接阶码与尾数
xq = (xq&0x807fffff)|((exponent1&0xff)<<23);
return *(float*)&xq;
}
}


float my_fadd(float x1, float x2){
float res;
int temp1, temp2;
if(!(((*(int*)&x1)&0x80000000)) && !(((*(int*)&x2)&0x80000000))){
//if x1>0 && x2>0 then x1+x2
res = inter_fadd(x1, x2);
}else if((((*(int*)&x1)&0x80000000)) && (((*(int*)&x2)&0x80000000))){
//if x1<0 && x2<0 then -(|x1| + |x2|)
temp1 = (*(int*)&x1)&0x7fffffff;
temp2 = (*(int*)&x2)&0x7fffffff;
res = inter_fadd(*(float*)&temp1, *(float*)&temp2);
temp1 = (*(int*)&res) ^ 0x80000000; //符号取反
res = *(float*)&temp1;
}else if(!(((*(int*)&x1)&0x80000000)) && (((*(int*)&x2)&0x80000000))){
//if x1>0 && x2<0 then x1 - |x2|
temp2 = (*(int*)&x2)&0x7fffffff;
res = inter_fminus(x1, *(float*)&temp2);
}else if((((*(int*)&x1)&0x80000000)) && !(((*(int*)&x2)&0x80000000))){
//if x1<0 && x2>0 then x2 - |x1|
temp1 = (*(int*)&x1)&0x7fffffff;
res = inter_fminus(x2, *(float*)&temp1);
}else{
res = 0.0f;
}

return res;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C 浮点转定点