首页 > 技术知识 > 正文

用过DSP的应该都知道Q格式吧;

1 前言

2 Q数据的表示

2.1 范围和精度

2.2 推导

3 Q数据的运算

3.1 0x7FFF

3.2 0x8000

3.3 加法

3.4 减法

3.5 乘法

3.6 除法

4 常见Q格式的数据范围

5 0x5f3759df

6 总结

1 前言

Q格式是二进制的定点数格式

,相对于浮点数,Q格式指定了相应的小数位数和整数位数,在没有浮点运算的平台上,可以更快地对浮点数据进行处理,以及应用在需要恒定分辨率的程序中(浮点数的精度是会变化的);

需要注意的是Q格式是概念上小数定点,通过选择常规的二进制数整数位数和小数位数,从而达到所需要的数值范围和精度,这里可能有点抽象,下面继续看介绍。

2 Q数据的表示

2.1 范围和精度

定点数通常表示为,其中复制m为整数个数,复制n为小数个数,其中最高位位符号位并且以二进制补码的形式存储;

范围: 精度:

无符号的用表示;

范围: 精度:

2.2 推导

无符号Q格式数据的推导这里以一个复制16位无符号整数为例,所能表示的最大数据的二进制形式如下图所示;

Q格式的表示方式以及相应的运算-qy格式怎样转换成无损音乐 所以不难看出,的范围大小和精度;根据等比数列求和公式得到,整数域最大值如下:

小数域最大值如下:

因此的范围满足 ;

有符号Q格式数据的推导

这里以一个复制16位有符号整数为例,所能表示的最大数据的二进制形式如下图所示;

Q格式的表示方式以及相应的运算-qy格式怎样转换成无损音乐1

所以不难求出,的范围大小和精度;根据等比数列求和公式得到,整数域最大值如下:

小数域最大值如下:

因此最大能表示的数为:;

所能表示的最小数据的二进制形式如下图所示;

Q格式的表示方式以及相应的运算-qy格式怎样转换成无损音乐2

可以从图中看到,该数表示为;

补充一下:负数在计算机中是补码的形式存在的,复制补码=反码+1,符号位为复制1则表示为负数;

那么复制-4该如何表示呢?

以复制8 bit数据为例,如下所示;

原码:复制0B 0000 100

反码:复制0B 1111 011

补码:复制0B 1111 100

综上,可以得到有符号的范围是:

3 Q数据的运算

3.1 0x7FFF

最大数的十六进制为复制0x7FFF,如下图所示;

Q格式的表示方式以及相应的运算-qy格式怎样转换成无损音乐1

3.2 0x8000

最小数的十六进制为复制0X8000,如下图所示;

Q格式的表示方式以及相应的运算-qy格式怎样转换成无损音乐2

上述这两种情况,下面都会用到。

3.3 加法

加法和减法需要两个Q格式的数据定标相同,即和满足以下条件;

复制int16_tq_add(int16_ta,int16_tb) { returna+b; }

上面的程序其实并不安全,在一般的DSP芯片具有防止溢出的指令,但是通常需要做一下溢出检测,具体如下所示;

复制//https://great.blog.csdn.net/ int16_tq_add_sat(int16_ta,int16_tb) { int16_tresult; int32_ttmp; tmp=(int32_t)a+(int32_t)b; if(tmp>0x7FFF) tmp=0x7FFF; if(tmp< -1*0x8000) tmp=-1*0x8000; result=(int16_t)tmp; returnresult; }

3.4 减法

类似于加法的操作,需要相同定标的两个Q格式数进行相减,但是不会存在溢出的情况;

复制//https://great.blog.csdn.net/ int16_tq_sub(int16_ta,int16_tb) { returna-b; }

3.5 乘法

乘法同样需要考虑溢出的问题,这里通过复制sat16函数,对溢出做了处理;

复制//https://great.blog.csdn.net/ //precomputedvalue: #defineK(1<< (Q – 1)) //saturatetorangeofint16_t int16_tsat16(int32_tx) { if(x>0x7FFF)return0x7FFF; elseif(x< -0x8000)return-0x8000; elsereturn(int16_t)x; } int16_tq_mul(int16_ta,int16_tb) { int16_tresult; int32_ttemp; temp=(int32_t)a*(int32_t)b;//resulttypeisoperandstype //Rounding;midvaluesareroundedup temp+=K; //Correctbydividingbybaseandsaturateresult result=sat16(temp>>Q); returnresult; }

3.6 除法

复制//https://great.blog.csdn.net/ int16_tq_div(int16_ta,int16_tb) { /*pre-multiplybythebase(UpscaletoQ16sothattheresultwillbeinQ8format)*/ int32_ttemp=(int32_t)a<< Q;     /*Rounding:midvaluesareroundedup(downfornegativevalues).*/ /*ORcomparemostsignificantbitsi.e.if(((temp>>31)&1)==((b>>15)&1))*/ if((temp>=0&&b>=0)||(temp< 0&&b< 0)){ temp+=b/2;/*ORshift1biti.e.temp+=(b>>1);*/ }else{ temp-=b/2;/*ORshift1biti.e.temp-=(b>>1);*/ } return(int16_t)(temp/b); }

4 常见Q格式的数据范围

定点数和浮点数转换的关系满足以下公式:

其中为,复制m表示整数位数,复制n表示小数位数;

复制#include #include #include intmain() { //0111111111111111 int16_tq_max=32767;//0x7FFF //1000000000000000 int16_tq_min=-32768;//0x8000 floatf_max=0; floatf_min=0; printf(” “); for(int8_ti=15;i>=0;i–){ f_max=(float)q_max/pow(2,i); f_min=(float)q_min/pow(2,i); printf(” |Q%d|Q%d.%d|%f|%f| “, i,(15-i),i,f_max,f_min); } return0; }

运行得到结果如下所示;Q格式的表示方式以及相应的运算-qy格式怎样转换成无损音乐3

Q Qmn Max Min Q 15 Q 0.15 0.999969 -1.000000 Q 14 Q 1.14 1.999939 -2.000000 Q 13 Q 2.13 3.999878 -4.000000 Q 12 Q 3.12 7.999756 -8.000000 Q 11 Q 4.11 15.999512 -16.000000 Q 10 Q 5.10 31.999023 -32.000000 Q 9 Q 6.9 63.998047 -64.000000 Q 8 Q 7.8 127.996094 -128.000000 Q 7 Q 8.7 255.992188 -256.000000 Q 6 Q 9.6 511.984375 -512.000000 Q 5 Q 10.5 1023.968750 -1024.000000 Q 4 Q 11.4 2047.937500 -2048.000000 Q 3 Q 12.3 4095.875000 -4096.000000 Q 2 Q 13.2 8191.750000 -8192.000000 Q 1 Q 14.1 16383.500000 -16384.000000 Q 0 Q 15.0 32767.000000 -32768.000000

5 0x5f3759df

Q格式虽然十分抽象,但是且看看这个数字0x5f3759df,感觉和Q格式有某种联系,它是雷神之锤3中的一个算法的魔数,毕竟游戏引擎需要充分考虑到效率,具体的由来可以看一下论文复制《Fast Inverse Square Root》,下面是源码中剥出来的快速平方根算法;

复制floatQ_rsqrt(floatnumber) { longi; floatx2,y; constfloatthreehalfs=1.5F; x2=number*0.5F; y=number; i=*(long*)&y;//evilfloatingpointbitlevelhacking i=0x5f3759df-(i>>1);//whatthefuck? y=*(float*)&i; y=y*(threehalfs-(x2*y*y));//1stiteration //y=y*(threehalfs-(x2*y*y));//2nditeration,thiscanberemoved #ifndefQ3_VM #ifdef__linux__ assert(!isnan(y));//bk010122-FPE? #endif #endif returny; }

6 总结

本文介绍了Q格式的表示方式以及相应的运算,另外需要注意在Q格式运算的时候,两者定标必须相同,对于数据的溢出检测也要做相应的处理。

审核编辑:汤梓红

猜你喜欢