Q格式是二進制的定點數格式,其中會標示小數位元(也可能包括整數位元)的長度。例如Q15數表示分數部份有15個位元,而Q1.14數表示1個整數位元以及14個小數位元。
針對有號的定點數,有二種Q格式的表示方式。其中一種是將符號位元算在整數位元裏,但另外一種就不是。例如,16位元的有號整數(無小數位元)可以表示為Q16.0或Q15.0。因此,在用說明Q格式的有號定點數字時,可能也需要一併標示總位元數(在此處為16)。
特點
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格式數字的解像度不隨數字大小而不冋。
轉換
若要將浮點數(例如IEEE 754)轉換為Qm.n的格式:
- 將浮點數乘以2n
- 四捨五入到最接近的整數
若要將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);
}
相關條目
參考資料
延伸閱讀
外部連結
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.