mpe*_*kov 9 c++ fixed-point multiplication
我遇到过这个函数:
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;
}
Run Code Online (Sandbox Code Playgroud)
内联评论是我的.似乎所有它正在做的是将两个参数相乘.这是正确的,还是还有更多呢?为什么要以这种方式完成?
Der*_*ter 15
这些参数不代表整数.它们以定点格式表示实数,小数点右侧为15位.例如,1.0由1 << 15 = 0x8000表示,0.5表示0x4000,-0.5表示0xC000(或32位的0xFFFFC000).
添加定点数很简单,因为您只需添加它们的整数表示.但是如果你想要乘法,你首先必须将它们乘以整数,但是你在小数点的右边有两倍的位数,所以你必须通过移位来丢弃多余的位数.例如,如果你想以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
Run Code Online (Sandbox Code Playgroud)
总而言之,你可以像这样进行乘法运算:
return (o32 * o16 + 0x4000) >> 15;
Run Code Online (Sandbox Code Playgroud)
但是有一个问题.在C++中,乘法的结果与其操作数具有相同的类型.因此o16被提升到相同的大小o32,然后它们相乘以获得32位结果.但这会抛弃最高位,因为产品需要16 + 32 = 48位才能准确表示.一种方法是将操作数转换为64位然后相乘,但这可能会更慢,并且在所有计算机上都不支持.因此,它会o32分成两个16位,然后在32位中进行两次乘法,并将结果组合在一起.
| 归档时间: |
|
| 查看次数: |
757 次 |
| 最近记录: |