单⽚机浮点乘除法优化措施及防⽌分⼦数据溢出单⽚机以性价⽐为特点,随着能源⾏业的发展,单⽚机在数字能源中的运⽤越来越⼴泛。最近学习了如何低端机上实现浮点运算。
1、前⾔
⽬前,⼤多数的单⽚机不具有浮点运算单元(FPU)。
TI公司的tms320f28335具有FPU,但是在进⾏⼀个浮点除法运算时,需要1.5us的时间,这在实时控制系统中是不太能接受的。
不具有浮点运算的单⽚机,需要将浮点运算转换为可以接受的整形运算。
2、整形运算概述
单⽚机主要分为8位机、16位机和32位机,使⽤最多的就是16位机。
16位机中变量类型 int 是16位的,也就是说:16位机使⽤16位的0或者1组合表⽰数据。
32位机中变量类型 int 是32位的,也就是说:32位机使⽤32位的0或者1组合表⽰数据。
3、浮点数的近似转换
在单⽚机中,浮点数乘除运算可以近似⽤乘以⼀个整数然后除以2的n次⽅表⽰。
例如:
0.25 = 1 >> 2;
0.5 = 1 >> 1;
0.75 = 3 >>2;
其他的浮点数以此类推。
⼀个浮点数可以有多种近似替换的⽅案,每种替换⽅案的精度不⼀样。
⽐如:
0.8 可以近似等于3>>2(0.75),也可以近似等于13>>4(0.8125);
明显可以看到,使⽤13>>4替换0.8⽐3>>2的精度要⾼些。但是前者更容易造成数据位溢出。
4、防⽌数据溢出
步骤三的转换也是有前提条件的:变量乘了整数后防⽌数据超过最⼤值。
如果整形变量是16位的,那么它乘以⼀个数后,它也必须是16位的,不能超出原有变量的数据类型的范围。
下⾯测试案例:
//定义变量类型
unsigned int a;
unsigned int b;
unsigned long c;
unsigned int d;
//测试⽅法
a = (1024*1024)>>10;
b = ((long)(1024*1024))>>10;
c = (1024*1024)>>10;
d = __builtin_muluu(1024,1024)>>10;
//编译警告
Test.c:101:15: warning: integer overflow in expression
Test.c:102:21: warning: integer overflow in expression
Test.c:103:14: warning: integer overflow in expression
//调试变量结果
a = 0
b = 0
c = 0
浮点型变量floatd = 1024
在16位单⽚机的C编译器的作⽤下,由上⾯的测试结果显⽰,仅仅只有第四种输出正确结果。
其他三种,不管是强制数据转换,还是设置为long型的变量,导致输出结果都不正确。
可能:
在这款单⽚机中,内存的最⼤位数位16位吧,如果需要超出16位运算结果的数据,就会报错。
或者只能按照该单⽚机⾃带的函数处理数据吧。
5、与浮点Q变换的区别
浮点数a转为定点数b是:b = (int)a*2n
定点数b转为浮点数a是:a = (float)a>>n
Q变换固定了n的位数,因此,截断误差也是固定的。⼀般,Q变换是把浮点数全部转为定点数参与运算,最后转为才转为浮点数;
上述提到的变换,截断误差取决于具体乘以的数和参数n;,这种变换,参与运算的等效为⼀个浮点数。
注意事项:
上述优化措施有⼀个很⼤的弊端,">>"运算很容易造成数据精度的丢失。
当⼀个整数A,乘以⼀个⽐1/A还⼩的数的时候,经过位移运算后,变为零。
⽐如:
对于系数0.75:
1*0.75 = 0.75 转化为 1*3>>2 = 0; 丢失数值0.75,相对误差100%;
2*0.75 = 1.5 转化为 2*3>>2 = 1;丢失数值0.5,相对误差为33.3%;
10*0.75 = 7.5 转化为 10*3>>2 = 7; 丢失数值0.5,相对误差为6.6%;
20*0.75 = 15 转化为 20*3>>2 = 15; 丢失数值0,相对误差为0%;
100*0.75 = 75 转化为100*3>>2=75; 丢失数值0,相对误差为0%;
200*0.75 = 150 转化为 200*3>>2 = 150; 丢失数值0,相对误差为0%;
对于系数0.25:
1*0.25 = 0.25 转化为 1>>2 = 0; 丢失数值0.25,相对误差100%;
2*0.25 = 0.5 转化为 2>>2 = 0;丢失数值0.5,相对误差为100%;
10*0.25 = 2.5 转化为 10>>2 = 2; 丢失数值0.5,相对误差为25%;
20*0.25 = 5 转化为 20>>2 = 5; 丢失数值0,相对误差为0%;
100*0.25 = 25 转化为100>>2=25; 丢失数值0,相对误差为0%;
200*0.25 = 50 转化为 200>>2 = 50; 丢失数值0,相对误差为0%;
对于系数0.125:
1*0.125 = 0.125 转化为 1>>3 = 0; 丢失数值0.125,相对误差100%;
2*0.125 = 0.25 转化为 2>>3 = 0;丢失数值0.25,相对误差为100%;
8*0.125 = 1 转化为 8>>3 = 1; 丢失数值0,相对误差为0%;
9*0.125=1.125 转化为9>>3 = 1; 丢失数值0.125,相对误差为11.11%
10*0.125 = 1.25 转化为 10>>3 = 1;丢失数值0.25,相对误差为20%;
20*0.125 = 2.5 转化为 20>>3= 2; 丢失数值0,相对误差为20%;
100*0.125 = 12.5 转化为100>>3=12; 丢失数值0.5,相对误差为4%;
150*0.125 =18.75 转化为150>>3=18; 丢失数值0.75,相对误差为4%;
180*0.125=22.5 转换为180>>3=22; 丢失数值0.5,相对误差为2.22%; 200*0.125 = 25 转化为 200>>3= 25; 丢失数值0,相对误差为0%;
因此,
上述思路,对于乘同以⼩于1的系数(被乘数),需要整数A不能太⼩,
总结:分⼦防溢出,系数防丢失,我太难了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论