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

这里默认用的是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;
}
时间: 2024-08-01 18:37:52

浮点转定点算法-加法运算的相关文章

数据结构和算法-一元多项式运算算法(加法)

算法名称:一元多项式算法 算法介绍: 加法运算:将具有与相同幂项的系数相加即可得到合并后的多项式.若某个幂项只存在于一个多项式中,则直接合并到结果中 举例 利用代码实现 这里主要使用了链表,通过3个函数来进行操作.分别是Inpu函数,Add运算函数,打印函数. 代码: /*采用链表的方式*/ #include<stdio.h> #include<stdlib.h> #include<limits.h> typedef struct polyn //定义多项式的结构 {

如果系统要使用超大整数(超过long长度范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算

package interview_10_10; import org.junit.Test; public class T1 { /** * 如果系统要使用超大整数(超过long长度范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算). */ @Test public void test1() { String number1 = "4324328732789"; String number2 = "2383244324324325898

图解算法:单向链表做加法运算

问:给出两个非空的链表,来表示两个非负的整数.其中,它们各自的位数是按照逆序的方式存储的,并且每个结点只能存储一位数字.将这两个链表相加起来,返回一个新的链表,表示他们之和. 例如:342 + 465 = 807 两数相加这道题,处理的就是最简单的数学加法运算,只是它是建立在链表的基础之上,所以难度在于对链表的处理. 加法运算,除了每一位的加法之外,还需要考虑进位的情况.针对这道题来说,链表的每一个结点存储一位数字,并且是基于自然数字逆序存储,也就是链头到链尾保持低到高位的顺序,这样就等于,进位

[算法]位运算问题之三(实现加减乘除)

题目: 给定32位整数a和b,可正.可负.可0,不能使用算术运算符,可分别实现a和b的加减乘除运算. 加法运算: 无进位相加: a: 001010101 b: 000101111 a^b 001111010 只考虑进位: a   001010101 b   000101111 (a&b)<<1 000001010 把完全不考虑进位的相加值与只与考虑进位的产生值再相加,就是最后的结果.重复这样的过程,直到进位产生的值完全消失,说明所有的过程都加完了. public static int

高精度计算(二) /*高精度的加法运算*/

例 高精度加法运算 输入正整数 a 和 b,输出 a+b 的值.0<a,b<=10^250 输入: 第一行:a 第二行:b   输出:a+b 的和. 样例输入: 99    999 样例输出: 1098 分析: (1)加法运算      -- a[7]  a[6]  a[5]  a[4]  a[3]  a[2]  a[1] -+-   0      0    b[5]  b[4]  b[3]  b[2]  b[1] ----------------------------------    

4个线程例子,2个线程对同一数字加法运算另外2个线程对同一共享数字减法运算

package com.saic.grape.controller; public class Data { private int j = 0; /** * 加法 */ public synchronized void inc() { j++; System.out.println("inc 加法运算>>" + j); } /** * 减法 */ public synchronized void dec() { j--; System.out.println("

[leetcode] Sum of Two Integers--用位运算实现加法运算

问题: Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -. Example: Given a = 1 and b = 2, return 3. 分析: 这里要求我们不能用加法.减法等运算符来实现加法运算.这里应该使用位运算来实现加法运算,实际上,这也是计算机CPU内部实现加法运算的方案. x XOR y真值表: x y output 0 0 0 0 1 1

[PAT] 一元多项式的乘法与加法运算 C语言实现

[PAT] 02-线性结构1 一元多项式的乘法与加法运算 设计函数分别求两个一元多项式的乘积与和. 输入格式: 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数).数字间以空格分隔. 输出格式: 输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数.数字间以空格分隔,但结尾不能有多余空格.零多项式应输出0 0. 输入样例: 4 3 4 -5 2 6 1 -2 0 3 5 20 -7 4 3 1 输出

(笔试题)只用逻辑运算实现加法运算

题目: 如题所示 思路: 逻辑运算,即二进制运算,无外乎与&.或|.非~.异或^以及移位>>,<<等操作: 而加法运算,在十进制中,只有按位相加以及进位两个操作. 从二进制角度也一样,就是bit位相加,加上相应的进位. 1.bit位相加,通过逻辑运算的异或操作可以实现,如0+1=1,1+0=1,0+0=0: 2.进位运算,通过逻辑运算的与操作可以实现,如1+1=1,因为进位是往高位+1,因此需要将进位结果左移一位. 将上述两个操作再做加法运算,就是加法运算的结果,这是一个递