概述
Original Source:
http://www.cnblogs.com/s_agapo/archive/2012/03/20/2407332.html
http://blog.csdn.net/sonictl/article/details/9018681
原文基于信号处理,本文对原文进行了精简和勘误,主要就浮点转定点运算的思想及实现进行说明:
1. 简介:
采用定点数进行数值运算,其操作数一般采用整型数来表示。
一个整型数的最大表示范围取决于运算芯片所给定的字长,一般为16位或24位。
显然,字长越长,所能表示的数的范围越大,精度也越高。如无特别说明,本文均以16位字长为例。
参与运算的数以二进制补码形式表示。每个16位数用一个符号位来表示数的正负,0表示数值为正,1则表示数值为负。
其余15位表示数值的大小。
1.1 示例:
二进制数 0 010000000000011 B = 8195
二进制数 1 111111111111100 B = -4
1.2 定点表示
参与数值运算的数为16位的整型数。但在许多情况下,数学运算过程中的数不一定都是整数。
应该说,运算芯片本身无法处理小数。关键就是由程序员来确定一个数的小数点处于16位中的哪一位。这就是数的定标。
{通过设定小数点在16位数中的不同位置,就可以表示不同大小和不同精度的小数}
数的定标有Q表示法和S表示法两种。下面列出了一个16位数的16种Q表示、S表示及它们所能表示的十进制数值范围:
Q表示 S表示 十进制数表示范围
Q15 S0.15 -1≤x≤0.9999695
Q14 S1.14 -2≤x≤1.9999390
Q13 S2.13 -4≤x≤3.9998779
Q12 S3.12 -8≤x≤7.9997559
Q11 S4.11 -16≤x≤15.9995117
Q10 S5.10 -32≤x≤31.9990234
Q9 S6.9 -64≤x≤63.9980469
Q8 S7.8 -128≤x≤127.9960938
Q7 S8.7 -256≤x≤255.9921875
Q6 S9.6 -512≤x≤511.9804375
Q5 S10.5 -1024≤x≤1023.96875
Q4 S11.4 -2048≤x≤2047.9375
Q3 S12.3 -4096≤x≤4095.875
Q2 S13.2 -8192≤x≤8191.75
Q1 S14.1 -16384≤x≤16383.5
Q0 S15.0 -32768≤x≤32767
1.3 定点表示示例:
同样一个16位数,若小数点设定的位置不同,它所表示的数也不同(首位为符号位):
16进制数2000 H= 二进制数0 010 0000 0000 0000 B= 十进制数8192, Q0表示法
16进制数 2000 H= 二进制数0 010 0000 0000 0000 B= 十进制数0.25 , Q15表示法
2. 浮点定点转换:
不同的Q所表示的数不仅范围不同,而且精度也不相同。
Q越大,数值范围越小,但精度越高;相反,Q越小,数值范围越大,但精度就越低。
E.g.
Q0 的数值范围是-32768到+32767,其精度为1;而Q15的数值范围为-1到0.9999695,精度为1/32768=0.00003051。
因此,对定点数而言,数值范围与精度是一对矛盾。
一个变量要想能够表示比较大的数值范围,必须以牺牲精度为代价;而想精度提高,则数的表示范围就相应地减小。
在实际的定点算法中,为了达到最佳的性能,必须充分考虑到这一点。
2.2 转换关系:
浮点数与定点数的转换关系可表示为:
浮点数(Fx)转换为定点数(Ix):Ix = (int)x* 2^Q
定点数(Ix)转换为浮点数(Fx):Fx= (float)Ix*2^(-Q)
2.3 转换示例:
浮点数 Fx = 0.5,定标 Q = 15,则定点数:
Ix = floor(0.5*32768) = 16384
反之,一个用 Q = 15 表示的定点数Ix = 16384,其浮点数为:
Fx = 16384 * 2^(-15) = 16384 / 32768 = 0.5
浮点数转换为定点数时,为了降低截尾误差,可以在取整前可以先加上0.5,视情况而定。
3. C语言实现定点预算模拟:
将浮点加法/减法转化为定点加法/减法时最重要的一点就是必须保证两个操作数的定标:
若两者不一样,则在做加法/减法运算前先进行小数点的调整。
为保证运算精度,需使Q值小的数调整为与另一个数的Q值一样大。
此外,在做加法/减法运算时,必须注意结果可能会超过16位表示。
如果加法/减法的结果超出16位的表示范围,则必须保留32位结果,以保证运算的精度,否则可能会出现严重的精度丢失。
3.1 结果不超过16位的定点加法描述:
// 设x的Q值为Qx,y的Q值为Qy,且Qx > Qy,加法/减法结果z的定标值为Qz
// 所以定点加法可以描述为:
int x,y,z;
long temp; // 临时变量
temp = y << (Qx - Qy);
// Q大-Q小,Q大的变量分辨率更高,Q小的左移增加其Q
temp = x + temp;
z = (int)(temp >> (Qx - Qz)); // if Qx >= Qz
z = (int)(temp << (Qz - Qx)); // if Qx <= Qz
E.g.
// 设x = 0.5,y = 3.1,则浮点运算结果为z = x+y = 0.5+3.1 = 3.6;
// Qx = 15,Qy = 13,Qz = 13,则定点加法为:
x = 16384;y = 25395;
temp = 25395 << 2 = 101580;
temp = x+temp = 16384+101580 = 117964;
z = (int)(117964L >> 2) = 29491;
// 因为z的Q值为13,所以定点值z = 29491即为浮点值z = 29491/8192 = 3.6。
More Examples.
Here.
3.2 定点乘法:
int x,y,z;
long temp;
temp = (long)x;
z = (temp×y) >>(Qx+Qy-Qz);
E.g.
// 设x = 18.4,y = 36.8,则浮点运算值为z = 18.4×36.8 = 677.12;
// 根据上节,得Qx = 10,Qy = 9,Qz = 5,所以
x = 18841;y = 18841;
temp = 18841L; // Long int
z = (18841L * 18841) >> (10+9-5) = 354983281L >> 14 = 21666;
// 因为z的定标值为5,故定点 z = 21666即为浮点的 z = 21666/32 = 677.08 产生了精度损失
3.3 混合表示法:
许多情况下,运算过程中为了既满足数值的动态范围又保证一定的精度,就必须采用Q0与Q15之间的表示法。
比如,数值1.2345,显然Q15无法表示,而若用Q0表示,则最接近它的数是1,精度无法保证。因此,数1.2345最佳的表示法是Q14。
一般的,若一个数的整数位为 i位,小数位为 j 位,另一个数的整数位为 m 位,小数位为 n 位,则这两个数的乘积为 ( i + m ) 位整数位和 (j + n) 位小数位。这个乘积的最高16位可能的精度为( i + m )整数位和(15 - i - m)小数位。
但是,若事先了解数的动态范围,就可以增加数的精度。
例如,程序员了解到上述乘积不会大于1.9999390,就可以用Q14数表示乘积,而不是理论上的最佳情况Q13。
最后
以上就是潇洒黄豆为你收集整理的浮点转定点运算的全部内容,希望文章能够帮你解决浮点转定点运算所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复