这里默认用的是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; }
原文地址:http://blog.csdn.net/chinazgr/article/details/24652267