本文介绍Q格式数据,也叫定点小数相关知识。
Q格式数据在MCU,FPGA,定点DSP经常出现,因为这些场合受限于速度,性能,运算能力都不适合做浮点数运算,但有时又会涉及到小数的运算,这时就需要用到Q格式数据,也就是经过缩放的小数,即定点小数。
1.原理
定点小数其实就是用整数来表示按比例缩放后的小数。和我们通常为了用整数表示0.123,进行放大10^2倍,用123这个整数来进行表示是一个道理,只是在计算机中数据通常采用二进制,这里的缩放是2^n而已。
通常我们用Qn来表示定点小数,n代表小数的个数,如Q15,Q8,Q10,分别表示有15个bit,8个bti,10个bit来表示小数,相应的缩放比例分别为:32768,256,1024。如果我们用的是int32_t的数据来表示的话,那么相应的整数部分(补码)就包括:17个bit,24个bit,22个bit。
另外,也有其他资料用Qm.n来对定点小数进行表示,其中m表示整数的个数(不包含符号位),n表示小数的个数,共需要m+n+1位来表示这个数据,多的1位用来表示符号位。如:Q0.15,Q11.20。
注意:
1)小数的位数决定了分辨率,而整数部分位数决定了数据的表示范围
2)如果表示的数据是无符号数,整数部分表示的范围会有所不同
2.范围
这里为了计算方便,我们用n来表示Q格式数据的总位数,m来表示小数的位数。这样,
整数部分位数:n-m
小数部分位数:m
1)有符号数
整数部分范围:-2^(n-m-1) to 2^(n-m-1)-1
小数部分范围:0 to 1-2^(-m)
这样,总的范围为:
-2^(n-m-1) to 2^(n-m-1)-2^(-m)
2)无符号数
整数部分范围:0 to 2^(n-m)-1
小数部分范围:0 to 1-2^(-m)
这样,总的范围为:
0 to 2^(n-m)-2^(-m)
3.分辨率
分辨率与小数的位数有关,分辨率为(m为小数个数):1/2^m
分辨率需要综合考虑整数的表示范围及实际情况(数据精度)进行设定。
例:
Q8格式数据分辨率为:1/2^8=0.003
Q10格式数据分辨率为:1/2^10=0.001
Q20格式数据分辨率为:1/2^20=0.000001
4.运算
1)加法:需转换成相同的Q格式才能相加,如2个Q7格式才可以相加
2)减法:需转换成相同的Q格式才能相减,如2个Q7格式才可以相减
3)乘法:不同Q格式的数据相乘,相当于Q值相加,即Q7数据乘以Q6数据后的结果为Q13格式的数据,如果赋值给一个Q10格式的数据则需要右移2位
4)除法:不同Q格式的数据相除,相当于Q值相减
5)左移:相当于Q值增加
6)右移:相当于Q值减少
5.溢出与舍入
在进行运算时需要考虑溢出,即2个数据运算后的大小有没有超过赋予的变量值。舍入需要考虑进行缩放后的数据是直接截断还是四舍五入。
6.技巧
1)对于运算过程中溢出问题,如相乘,相除,可以考虑将数据归1化(除以最大值),并采用最多小数位数的Q格式进行表示,因2个数都小于1,相乘,除都不会导致数据溢出。
2)数据在Q格式化过程中可以巧妙的利用移位操作,加快运算速度。如1.234,用Q16格式数据进行表示为:80871/65536,也可以:80871 >> 16。
7.例子
1)2个数据相加:
y=a+b
其中:a=1.358,b=12.386
y=1.358+12.386=13.744
采用int16_t的Q10数据进行处理:
a'=1.358*2^10=1391(这里进行四舍五入)
b'=12.386*2^10=12683(这里进行四舍五入)
y'=1391+12683=14074
y'的实际值需要除以2^10,为:14074/2^10=13.7441
可见,运算过程中其实是有一定的误差的
2)2个数据乘:
y=a*b
其中:a=1.358,b=12.386
y=1.358*12.386=16.820188
采用int16_t的Q10数据进行处理:
a'=1.358*2^10=1391(这里进行四舍五入)
b'=12.386*2^10=12683(这里进行四舍五入)
y'=1391*12683/2^10=17229(这里进行四舍五入)
y'的实际值需要除以2^10,为:17229/2^10=16.825
总结,本文介绍Q格式数据及相关运算。