2023年12月16日 星期六

Fixed-point arithmetic 定點運算

fixed-point 是一種小數表示方式,儲存固定位數小數。某個固定單位的部份,皆可視為小數。

閱讀時,有小數點分隔整數和小數。但在內部處理程式,並沒有實際的分隔,而由程式隱含定義位置。

低成本嵌入式處理器,沒有浮點運算單元,有些計算需要定點運算適當的 scaling 來達到可接受的動態範圍。定點運算可以比浮點運算更快、更高精確度,但寫程式需要更精確預測數值範圍,調整 scaling facotr,避免 overflow。

表示法

  • Qm.n:通常是有號數,不含 sign-bit,整數部份 m-bit,小數部份 n-bit。在 ARM,m 包含 sign-bit。
  • UQm.n:無號數,整數部份 m-bit,小數部份 n-bit。
  • Qn:小數部份 n-bit。

加法和減法:相同 scaling factor,結果 scaling factor 不變。overflow。

乘法:scaling factor 相乘。在二進位,通常使用 scaling factor that is a power of two,乘完後 scaling factor 可透過 shifting right 調整回來。Rounding 可在 shift 前加上 scaling factor 的一半。證明:round(x/y) = floor(x/y + 0.5) = floor((x + y/2)/y) = shift-of-n(x + 2^(n-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 += 1 << (Q - 1);
    // Correct by dividing by base and saturate result
    result = sat16(temp >> Q);

    return result;
}

除法 https://lirobo.blogspot.com/2021/08/rounding-integer-division.html

int16_t q_div(int16_t a, int16_t b)
{
    int32_t temp = (int32_t)a << Q;
    // Rounding: mid values are rounded up.
    if (((temp >> 31) & 1) == ((b >> 15) & 1)) {
        temp += b>>1; // round up
    } else {
        temp -= b>>1; // round down for negative value
    }
    return (int16_t)(temp / b);
}

參考

  • https://en.wikipedia.org/wiki/Fixed-point_arithmetic
  • libfixmath

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...