首页 > 代码库 > 浮点转定点算法-加法运算

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

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

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

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

  3. 定点加法运算。

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

    #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;
}


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