9

私はこの機能に遭遇しました:

static inline INT32 MPY48SR(INT16 o16, INT32 o32)
{
    UINT32   Temp0;
    INT32    Temp1;
    // A1. get the lower 16 bits of the 32-bit param
    // A2. multiply them with the 16-bit param
    // A3. add 16384 (TODO: why?)
    // A4. bitshift to the right by 15 (TODO: why 15?)
    Temp0 = (((UINT16)o32 * o16) + 0x4000) >> 15;
    // B1. Get the higher 16 bits of the 32-bit param
    // B2. Multiply them with the 16-bit param
    Temp1 = (INT16)(o32 >> 16) * o16;
    // 1. Shift B to the left (TODO: why do this?)
    // 2. Combine with A and return
    return (Temp1 << 1) + Temp0;
}

インラインコメントは私のものです。2 つの引数を乗算しているだけのようです。これは正しいですか、それとももっとありますか? なぜこれがそのような方法で行われるのでしょうか?

4

2 に答える 2

16

これらのパラメーターは整数を表していません。これらは、基数の右側に 15 ビットの固定小数点形式で実数を表します。たとえば、1.0 は 1 << 15 = 0x8000、0.5 は 0x4000、-0.5 は 0xC000 (または 32 ビットの 0xFFFFC000) で表されます。

整数表現を追加するだけでよいため、固定小数点数の追加は簡単です。ただし、乗算する場合は、最初にそれらを整数として乗算する必要がありますが、基数の右側に 2 倍のビットがあるため、シフトして超過分を破棄する必要があります。たとえば、32 ビット形式で 0.5 を単独で乗算する場合は、0x00004000 (1 << 14) を単独で乗算して 0x10000000 (1 << 28) を取得し、15 ビット右にシフトして 0x00002000 (1 < < 13)。精度を高めるには、最下位の 15 ビットを破棄するときに、切り捨てではなく、最も近い数値に丸めます。これを行うには、0x4000 = 1 << 14 を追加します。その後、破棄された 15 ビットが 0x4000 未満の場合は切り捨てられ、0x4000 以上の場合は切り上げられます。

 (0x3FFF + 0x4000) >> 15 = 0x7FFF >> 15 = 0
 (0x4000 + 0x4000) >> 15 = 0x8000 >> 15 = 1

要約すると、次のように乗算を実行できます。

 return (o32 * o16 + 0x4000) >> 15;

しかし、問題があります。C++ では、乗算の結果はそのオペランドと同じ型になります。Soo16は と同じサイズに拡張されo32、乗算されて 32 ビットの結果が得られます。しかし、この積は正確な表現のために 16 + 32 = 48 ビットを必要とするため、上位のビットが破棄されます。これを行う 1 つの方法は、オペランドを 64 ビットにキャストしてから乗算することですが、これは遅くなる可能性があり、すべてのマシンでサポートされているわけではありません。その代わりにo32、2 つの 16 ビットの断片に分割し、次に 32 ビットで 2 つの乗算を行い、結果を結合します。

于 2012-10-12T18:43:16.817 に答える
5

これは、固定小数点数の乗算を実装します。数値は、Q15 形式 (小数部分が 15 ビット) であると見なされます。

数学的に、この関数は を計算(o16 * o32) / 2^15し、最も近い整数に丸めます (したがって2^14、 を表す係数は1/2、数値を丸めるために数値に追加されます)。これは、32 ビットの結果を持つ符号なしおよび符号付きの 16 ビット乗算を使用します。これは、おそらく命令セットによってサポートされています。

各数値が最小値 (-2^15 と -2^31) を持つコーナー ケースが存在することに注意してください。この場合、結果 (2^31) は出力で表現できず、ラップされます (代わりに -2^31 になります)。との他のすべての組み合わせについてo16o32結果は正しいです。

于 2012-10-12T18:37:52.080 に答える