浮点转定点运算

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的数值范围为-10.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。

  • 14
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值