为什么用这种方式进行乘法运算
Why perform multiplication in this way?
我遇到了这个函数:
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;
}
内联评论是我的。似乎它所做的只是将这两个论点相乘。这是对的吗,还是还有更多?为什么要这样做?
这些参数不代表整数。它们以定点格式表示实数,基点右侧有15位。例如,1.0由1<lt;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<lt;14.然后,如果丢弃的15位小于0x4000,则向下取整,如果是0x4000或更大,则向上取整。
(0x3FFF + 0x4000) >> 15 = 0x7FFF >> 15 = 0
(0x4000 + 0x4000) >> 15 = 0x8000 >> 15 = 1
总之,你可以这样做乘法:
return (o32 * o16 + 0x4000) >> 15;
但有一个问题。在C++中,乘法运算的结果与其操作数具有相同的类型。因此,o16
被提升到与o32
相同的大小,然后将它们相乘以获得32位的结果。但这会丢弃最高位,因为乘积需要16+32=48位才能准确表示。一种方法是将操作数强制转换为64位,然后相乘,但这可能会更慢,而且并非所有机器都支持。因此,它将o32
分解为两个16位的片段,然后在32位中进行两次乘法运算,并组合结果。
这实现了定点数的乘法运算。这些数字被视为Q15格式(小数部分有15位)。
从数学上讲,该函数计算四舍五入到最接近的整数的(o16 * o32) / 2^15
(因此,表示1/2
的2^14
因子被添加到一个数字上以进行四舍五舍五入)。它使用32位结果的无符号和有符号16位乘法,这可能是指令集所支持的。
请注意,存在一个角情况,其中每个数字都有一个最小值(-2^15和-2^31);在这种情况下,结果(2^31)在输出中是不可表示的,并且被包裹起来(变为-2^31)。对于o16
和o32
的所有其他组合,结果是正确的。
- 如何在c++中为模板函数实例创建快捷方式
- 使用C++中的模板和运算符重载执行矩阵运算
- 如何在openssl-ecc中获取十六进制格式的私钥
- GCC本机矩阵运算库
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 如何将包含epoch时间的十六进制字符串转换为time_t
- 以螺旋方式打印矩阵的程序.(工作不好)
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 如何将一个ostringstream十六进制字符串字符对转换为单个unit8t等价的二进制值
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 创建引用向量的优雅方式
- 如何在C++中用std::cout正确显示带十六进制的字符串文本
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 通过错误处理,在C++中可靠地获得用户十六进制输入
- clang格式:宏的缩进
- 是否可以更改 Xcode 缩进注释行的方式
- 在十六进制编辑器中写入程序内存,并以编程方式读取
- 为什么用这种方式进行乘法运算
- C++ 中的十六进制按位运算