使用交叉乘法方法的32位小数乘法(无64位中间结果)

时间:2013-02-05 17:47:32

标签: multiplication fixed-point

我正在16位处理器上编程定点语音增强算法。在某些时候,我需要进行32位小数乘法。我已经阅读了有关逐字节进行32位乘法的其他帖子,我知道为什么这适用于Q0.31格式。但是我使用不同的Q格式和不同数量的小数位。

所以我发现对于小于16的小数位,这有效:

(low*low >> N) + low*high + high*low + (high*high << N)

其中N是小数位数。我已经读过low*low结果应该是无符号的以及低字节本身。通常,这给出了我想要的任何Q格式的结果,小于16的小数位。

现在,当小数位超过16时,它变得棘手。我已尝试了几个班次,low*lowhigh*high的不同班次我试图把它写在纸上,但我无法理解。

我知道这可能很简单,但整个想法都没有我,我会感激一些评论或指导!

2 个答案:

答案 0 :(得分:0)

这是相同的公式。对于N> 16,移位只是意味着你抛出一个完整的16位字,这个字会有过量或者过度下降。低*低&gt;&gt; N表示在乘法的32位结果的高位字中移位N-16位,并加到结果的低位字。高*高&lt;&lt; N表示只使用左移N-16的乘法结果的低位字,并加到结果的高位字。

答案 1 :(得分:0)

有一些想法在起作用。

首先,乘以2个较短的整数以产生更长的产品。考虑通过16位“一半”的乘法对2个32位整数进行无符号乘法运算,每个乘法产生一个32位乘积,总乘积为64位:

a * b =(a_hi * 2 16 + a_lo)*(b_hi * 2 16 + b_lo)=

a_hi * b_hi * 2 32 +(a_hi * b_lo + a_lo * b_hi)* 2 16 + a_lo * b_lo。

现在,如果你需要一个带符号的乘法,你可以用无符号乘法来构造它(例如从上面开始)。

假设&lt; 0和b&gt; = 0,a * signed b必须相等

2 64 - ((-a)* unsigned b),其中

-a = 2 32 - a(因为这是2的补码)

IOW,

a * 已签署 b =

2 64 - ((2 32 - a)* unsigned b)=

2 64 +(a * unsigned b) - (b * 2 32 ),其中2 64 因为我们只使用64位,所以可以丢弃。

以完全相同的方式,您可以为&gt; = 0和b signed b。 0并且必须得到对称结果:

(a * unsigned b) - (a * 2 32

你可以类似地表明对于&lt; 0和b <0 0有符号乘法可以用无符号乘法建立:

(a * unsigned b) - ((a + b)* 2 32

因此,首先将a和b乘以无符号,然后将&lt; 0,你从产品的前32位中减去b,如果b&lt; 0,你从产品的前32位中减去a,完成。


既然我们可以将32位有符号整数相乘并得到64位有符号的产品,那么我们最终可以转向小数。

现在假设a和b N位中的32位用于小数部分。这意味着如果你将a和b视为普通整数,它们将比它们实际代表的值大2 N 倍,例如1.0将看起来像2 N (或1 <&lt; N)。

所以,如果你乘以两个这样的整数,产品将是2 N * 2 N = 2 2 * N 倍比它应该代表的,例如1.0 * 1.0看起来像2 2 * N (或1 <&lt;(2 * N))。 IOW,普通整数乘法将使小数位数加倍。如果你想要产品 具有与被乘数相同的小数位数,你做什么?您将乘积除以2 N (或将其向右移位N位置右侧)。简单。


请注意,以防万一...

在C(和C ++)中,您不能合法地将变量向左或向右移动变量中包含的相同或更多位数。代码将编译,但不会像您期望的那样工作。因此,如果要移动32位变量,可以将其向左或向右移动0到31个位置(31是最大值,而不是32位)。

如果您将有符号整数移位,则不能合法地溢出结果。所有已签名的溢出都会导致未定义的行为。所以,你可能想坚持使用unsigned。

负有符号整数的右移是特定于实现的。它们可以进行算术移位或逻辑移位。哪一个,这取决于编译器。因此,如果您需要其中一个,您需要确保您的编译器直接支持它 或以其他方式实施。