Q格式
Q格式是二进制的定点数格式,其中会标示小数位元(也可能包括整数位元)的长度。例如Q15数表示分数部份有15个位元,而Q1.14数表示1个整数位元以及14个小数位元。
针对有号的定点数,有二种Q格式的表示方式。其中一种是将符号位元算在整数位元里,但另外一种就不是。例如,16位元的有号整数(无小数位元)可以表示为Q16.0或Q15.0。因此,在用说明Q格式的有号定点数字时,可能也需要一并标示总位元数(在此处为16)。
Q格式是几种广为使用的定点数中的一种。定点数常用在不支援浮点运算器的硬体,或是用在需要固定解析度的应用。
特点
Q格式用来标示定点数,储存以及运算都是以一般的二进位整数为基础来处理,因此允许标准的整数硬体/算术逻辑单元来进行有理数运算。程式设计者可以依应用需求,选定其整数位元数、小数位元数(以及资料总位元数),而之后定点数的范围以及解析度就会依整数位元数、小数位元数而不同。
有些DSP架构原生支持一些常用的Q格式(例如Q1.15),这种情形下,可以在一个指令下就进行四则运算,若是加减法,可以支援饱和运算,若是乘除法,可以有正规化的机能。不过大部份的DSP无此功能,若DSP架构不支持选定的Q格式,程式设计者就要自行再针对加减法进行饱和运算,针对乘除法进行正规化。
有号号Q格式的表示方式有两种,都写成Qm.n:
- Q表示这个数字是以Q格式表示,在德州仪器则用Q表示是有号的Q格式(Q是数学里表示有理数的字母)
- m.(可省略,若省略的话,假设是0或1)是数字在用二补数表示下的整数位元数,可能包括符位元,也可能不包括(这也是若m省略的话,假设是0或1的原因)。
- n是数字中小数的位元数,也就是二进位表示时,在小数点右边的二进位个数(若n = 0,表示Q格式数字是整数)。
一种表示方式将符号位元放在整数位元 m中一起计算[1][2],另一种则不是。确认方式可以将m和n相加,看是否等于数字位元数,若相等,表示其符号位元放在整数位元 m,若比数字位元数少1,表示其其符号位元独立计算。
此外,字母U可以放在Q前面,说明是无号数,例如UQ1.15,数值范围是0.0 to +1.999969482421875 (也就是)。
有号的Q格式数值会用二补数储存,正如大部份处理器处理整数的情形一样。在二补数中,会用符号位元填满没有用到数字位元。
针对给定的Qm.n格式(假设符号位元也算在m个位元内),用m+n位元的有号整数来处理,再考虑其中有n位元是表示小数:
- 其范围为
- 其解析度为
针对给定的UQm.n格式,用m+n位元的有号整数来处理,再考虑其中有n位元是表示小数:
- 其范围为
- 其解析度为
例如Q15.1格式的数字:
- 需要位元数为15+1 = 16位元
- 其范围为[-214, 214 - 2−1] = [-16384.0, +16383.5] = [0x8000, 0x8001 … 0xFFFF, 0x0000, 0x0001 … 0x7FFE, 0x7FFF]
- 其解析度为2−1 = 0.5
Q格式和浮点数不同,Q格式数字的解析度不随数字大小而不冋。
转换
浮点数到Q格式
若要将浮点数(例如IEEE 754)转换为Qm.n的格式:
- 将浮点数乘以2n
- 四舍五入到最接近的整数
Q格式到浮点数
若要将Qm.nQ格式的数数转换为浮点数:
- 将整数转换为浮点数
- 乘以2−n
数学运算
Q格式的数字是二个整数的比例:会储存分子,而分母固定是2n。
考虑以下的例子;
- Q8格式的分母是28 = 256
- 1.5等于384/256
- 会储存384,256不储存(因为是Q8格式,分母固定是256)
若Q格式的基底固定(n都相同),则Q格式的数学运算需维持分母不变。以下是二个相同Q格式数字和的运算。
因为分母是二的次幂,因此和二的次幂相乘可以表示为二进制下的左移,和二的次幂相除可以表示为二进制下的右移,很多处理器的左移和右移会比乘除法要快。
为了要维持乘法和除法的精度,中间值需要用双精度来储存,在转换回需要的Q格式数字之间,也需要先注意数值修约的处理。
两个不同Q格式基底的数字也可以相乘除,相乘除的数字也可以用另一个基底表示。以下是二个Q格式数字(分母)和(分母)的运算,运算结果的分母是。
若用C语言,相同Q格式基底数字四则运算对应的程式如下(以下的Q是表示小数部份的位元数)
加法
int16_t q_add(int16_t a, int16_t b)
{
return a + b;
}
有饱和
int16_t q_add_sat(int16_t a, int16_t b)
{
int16_t result;
int32_t tmp;
tmp = (int32_t)a + (int32_t)b;
if (tmp > 0x7FFF)
tmp = 0x7FFF;
if (tmp < -1 * 0x8000)
tmp = -1 * 0x8000;
result = (int16_t)tmp;
return result;
}
浮点数有±Inf,但Q格式没有,若不进行饱和处理,二个很大的正数相加,可能会变成一个很大的负数。若是用组合语言,可以用Signed Overflow旗标来避免C语言实现时需要的型态转换。
减法
int16_t q_sub(int16_t a, int16_t b)
{
return a - b;
}
乘法
// precomputed value:
#define K (1 << (Q - 1))
// saturate to range of int16_t
int16_t sat16(int32_t x)
{
if (x > 0x7FFF) return 0x7FFF;
else if (x < -0x8000) return -0x8000;
else return (int16_t)x;
}
int16_t q_mul(int16_t a, int16_t b)
{
int16_t result;
int32_t temp;
temp = (int32_t)a * (int32_t)b; // result type is operand's type
// Rounding; mid values are rounded up
temp += K;
// Correct by dividing by base and saturate result
result = sat16(temp >> Q);
return result;
}
除法
int16_t q_div(int16_t a, int16_t b)
{
/* pre-multiply by the base (Upscale to Q16 so that the result will be in Q8 format) */
int32_t temp = (int32_t)a << Q;
/* Rounding: mid values are rounded up (down for negative values). */
/* OR compare most significant bits i.e. if (((temp >> 31) & 1) == ((b >> 15) & 1)) */
if ((temp >= 0 && b >= 0) || (temp < 0 && b < 0)) {
temp += b / 2; /* OR shift 1 bit i.e. temp += (b >> 1); */
} else {
temp -= b / 2; /* OR shift 1 bit i.e. temp -= (b >> 1); */
}
return (int16_t)(temp / b);
}
相关条目
参考资料
- ^ ARM Developer Suite AXD and armsd Debuggers Guide. 1.2. 安谋控股. Chapter 4.7.9. AXD > AXD Facilities > Data formatting > Q-format. 2001 [1999]. ARM DUI 0066D. (原始内容存档于2017-11-04).
- ^ Chapter 4.7.9. AXD > AXD Facilities > Data formatting > Q-format. RealView Development Sui (PDF). 安谋控股. 2006: 4–24 [1999]. ARM DUI 0066G. (原始内容存档 (PDF)于2017-11-04).
延伸阅读
- Oberstar, Erick L. Fixed Point Representation & Fractional Math (PDF). 1.2. Oberstar Consulting. 2007-08-30 [2004] [2017-11-04]. (原始内容存档 (PDF)于2017-11-04). (Note: the accuracy of the article is in dispute; see discussion.)
外部链接
- Q-Number-Format Java Implementation. [2017-11-04]. (原始内容存档于2017-11-04).