float 转定点计算加法和乘法
来源:互联网 发布:风险矩阵应用 编辑:程序博客网 时间:2024/05/22 14:26
float 浮点数转成定点数计算其加法和乘法
需要注意的是,以下的程序是建立在下述条件为真的情况下的:
(sizeof(float) == 4 && sizeof(long long) == 8 && sizeof(int) == 4) == ture
也就是说,一定要保证float和int是占4个字节(32bits),long long是占8个字节(64bits)的。
1, 浮点数转定点乘法
void FixedPointMul(float&a, float& b, float& res){ int ia = *(int*)(&a); int ib = *(int*)(&b); //正负0的情况下,直接返回 if (ia == 0x80000000 || ia == 0x0 || ib == 0x80000000 || ib == 0x0) { res = 0.0f; return; } //实际尾数还要加上最前面的1,这里用Long long的原因是两个24位数的乘法,最多是48位,已超出int long long ma = (ia & 0x7fffff) | 0x800000; long long mb = (ib & 0x7fffff) | 0x800000; //码位 int ea = ((ia >> 23) & 0xff) - 0x7f; int eb = ((ib >> 23) & 0xff) - 0x7f; //mul long long mc = ma * mb;//相当于a<< (23-ea) a<<(23-eb) //计算阶码 //先计算最高有效位 int i = 0; long long tmp = mc; while (tmp != 0) { tmp >>= 1; i++;//得到MSB的位置 } int ec = i - 1 - (23 - ea + 23 - eb) + 0x7f; //再右移mc MSB 到第24位 //把MSB移位到第24位 //把MSB移位到第24位 if (i < 24) mc = (mc << (24 - i)) & 0xffffff; else mc = (mc >> (i - 24)) & 0xffffff; // //标记两个数的正负 int sa = 0; if ((ia & 0x80000000) ^ (ib & 0x80000000))//xor sa = 1;//negative //float //拼接成float int rc = 0x00000000; rc = rc | (mc & 0x7fffff); rc = rc | ((ec << 23) & 0x7fffffff); //判断正负 if (sa == 1) rc = rc | 0x80000000; res = *(float*)(&rc); return;}
2, 浮点转定点加法(减法可以认为是加上一个负数)
#ifndef MAX#define MAX(X,Y) ((X)>(Y) ? (X) : (Y))#endifvoid FixedPointAdd(float& a, float& b, float& res){ int ia = *(int*)(&a); int ib = *(int*)(&b); //考虑正负0的情况 if (ia == 0) { res = b; if(ib == 0x80000000) res = 0.0f; return; } if (ib == 0) { res = a; if (ia == 0x80000000) res = 0.0f; return; } //if ((ia & 0x7f800000 == 0x7f800000) | (ib & 0x7f800000 == 0x7f800000)); //实际尾数还要加上最前面的1 long long ma = (ia & 0x7fffff) | 0x800000; long long mb = (ib & 0x7fffff) | 0x800000; //码位 int ea = ((ia >> 23) & 0xff) - 0x7f; int eb = ((ib >> 23) & 0xff) - 0x7f; //正负 int sa = ia & 0x80000000; int sb = ib & 0x80000000; //移动到48位并加上符号运算 if (ea > eb) {//让较大的数的MSB移动到第48位,较小的数对应的移动 //这样的话,小数点对齐在哪里? ma <<= 24; //mb如何移动?//mb少移动:ea与eb的绝对值的差 mb <<= (24 - std::abs(ea - eb)); } else { mb <<= 24; ma <<= (24 - std::abs(ea - eb)); } //考虑符号 ma = (sa == 0 ? ma : -ma); mb = (sb == 0 ? mb : -mb); long long mc = ma + mb; int i = 0; long long tmp = 0; //结果符号 tmp = 0x8000000000000000; int sc = ((mc & tmp) == 0 ? 0 : 1); if (sc == 1)//说明结果是负数 { mc = -mc; } //计算阶码 //先计算最高有效位 tmp = mc; while (tmp != 0) { tmp >>= 1; i++;//得到MSB的位置 } //code int ec = 0x7f; if (ea > eb) ec += ea + (i - 48); else ec += eb + (i - 48); //把MSB移位到第24位 if (i < 24) mc = (mc << (24 - i)) & 0xffffff; else mc = (mc >> (i - 24)) & 0xffffff; // //float //拼接成float int rc = 0x00000000; rc = rc | (mc & 0x7fffff); rc = rc | ((ec << 23) & 0x7fffffff); //判断正负 if (sc == 1) rc = rc | 0x80000000; res = *(float*)(&rc); return;}
最后需要注意的是,float占4个字节的情况下,在二进制情况下,共有24bit数字是精确数字,转换到十进制数, 只有6位有效数字是绝对精确的,所以在两个float数字比较其误差时,应注意,第7位及以后的数字是无意义的。
比如说:12345.67888和12345.6999其实对于float的内存来说是一样的,但是它们之间的绝对误差是:0.02111,达到了2%。
再比如:123456.000和123456.9999,在float的内存上是一样的,但是,其绝对差为0.9999。
所以用绝对差来表示两个float数是否相近,是不合理的。
2 0
- float 转定点计算加法和乘法
- js加法和乘法的精确计算
- 高精度算式计算(加法和乘法)
- js加法和乘法的精确计算
- 大数加法和乘法
- 大数加法和乘法
- 高精度加法和乘法
- 多项式加法和乘法
- 加法和乘法
- 浮点转定点算法-加法运算
- 大数加法和大数乘法
- 大数加法和大数乘法
- 分数的加法和乘法
- 大数加法、减法和乘法
- 高精度(乘法和加法)
- 字符串实现加法和乘法
- js 中的加法和乘法
- 多项式的加法和乘法
- Hibernate学习笔记之ORM实体间关系“OneToOne”详解
- 九度OJ 1123 采药 0/1背包问题
- Servlet+JSP实现人员新增
- 安卓实现右滑返回效果
- 【NOIP2012借教室】(线段树区间操作)
- float 转定点计算加法和乘法
- php date函数各参数含义
- OCR文字识别可以帮你节省纸
- java对象和xml互转
- 判断素数(质数)
- MHA (二)
- PCIE接口理解
- 从mysql连接池中获取到失效连接的问题
- Implement strStr()