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

#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);
		//通过移位截断小数部分,保留整数部分
		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;
}

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

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

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

  3. 定点加法运算。

  4. 将上一步的运算结果还原为浮点表示。

转载于:https://my.oschina.net/u/200628/blog/227537

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值