二进制定点乘法

时间:2016-01-26 19:06:11

标签: vhdl fpga multiplication signed fixed-point

我正在实现一个VHDL 8位定点乘法模块,它返回一个8位截断数,但是当我手动乘法以测试它时我遇到了问题。当我想要乘以两个负数时会出现问题。

我尝试将两个正值乘以1.67 * 0.625~1.04(二进制乘法中为0.906)。

001.10101 -> 1.67
000.10100 -> 0.625
------------
000000.1110111010 = 000.11101 (truncated to 8bits = 0.906)

我尝试将负数和正数相乘(-0.875 * 3~2.62)

111.00100 -> -0.875
011.00000 -> 3
----------
010101.0110000000 = 101.01100 (truncated to 8bits = -2.625)

到目前为止,每个人都在正常工作。问题来了,我试图乘以两个负数。据我所知(除非我弄错了): - 将两个数相乘会得到两倍分辨率的结果(乘以两个8位数,得到一个16位数) - 固定点也会脱臼。在这个例子中,固定前有3位,之后有5位。这意味着在得到的数字中,固定点在点之前有6位数,在点之后有10位。

假设这一点,上述计算工作正常。但是当我尝试乘以两个负值(-0.875 * -1.91~1.67)

110.00010 -> -1.91 (1.9375)
111.00100 -> -0.875
------------
101011.0011001000 = 011.00110(truncated to 8 bits = 3.1875)

当然,我尝试了另一种负乘法(-2.64 * -0.875 = 2.31)

101.01011 -> -2.64
111.00100 -> -0.875
----------
100110.0001001100 = 110.00010 (truncated to 8bits = -1.9375)

显然,我做错了什么,但我无法看清我做错了什么。

PS :我还没有实现它。想到了我,我想出了我将如何去做,然后我尝试用一​​些简单的例子手工测试它。而且我也试过了更多的乘法。我想也许他们成功了,因为我很幸运,但显然不是,我尝试了几次乘法而且他们工作了。因此,在将两个负数相乘时,我可能会做错事,也许我会错误地将其截断?大概。

修改: 好的,我找到了一个Xilinx文档,说明当两个操作数为负数时如何进行乘法,here是链接。根据这个文档,为了这个文档,这只能在进行扩展乘法时完成。并且必须反转乘法的最后一个部分和,然后加1,它将得到正确的数字。

为了乘法,我使用了windows'程序员模式下的计算器,这意味着为了将8位相乘,我将数字放在计算器中,然后得到结果并截断它。如果它们适用于其他情况,则意味着Windows计算器正在进行直接乘法(将所有部分和加入,而不是反转最后的部分和)。所以,这意味着为了获得实际结果,我应该从最终结果中减去第一个操作数,然后添加第一个操作数reverse + 1

110.00010 -> -1.91 (1.9375)
111.00100 -> -0.875
------------
101011.0011001000
Which gave me the result: 000010.0111001000 = 010.01110(truncated to 8bits =2.43)

与另一个我想出了1.875的结果。那些输出并不是很好,但至少它们更接近我的预期。有没有其他方法可以更容易地做到这一点?

1 个答案:

答案 0 :(得分:2)

您的中间结果是错误的,因此,截断不能按预期工作。此外,如果中间结果的四个最高位在您的格式中相等,则截断只能在没有溢出的情况下进行。 您应该使用签名数据类型来进行乘法运算。

即便是你的第二个例子也是错误的。中间二进制结果010101.0110000000表示十进制数21.375,它不是-0.875和3的乘积。因此,让我们手动进行乘法运算:

    a     *     b      = -0.875 * 3 = -2.625
111.00100 * 011.00000
---------------------
          .  00000000  // further lines containing only zeros have been omitted
+         .01100000
+      011.00000
+     0110.0000
+   110100.000         // add -(2^2) * b  !
=   111101.0110000000  = -2.625  (intermediate result)
=      101.01100       = -2.625  after truncation

您必须在最后一个部分和中添加b的两个补码,因为' 1'在a的最顶部位表示值 - (2 ^ 2)= -4。这里可以截断没有溢出,因为中间结果的4个最顶部位是相等的。

现在是第三个例子

    a           b      = -1.9375 * -0.875 = 1.6953125
110.00010 * 111.00100 
--------------------- 
          .  00000000  // further lines containing only zeros have been omitted
+   111111.111100100   // sign-extended partial-sum
+   111110.0100        // sign-extended partial-sum
+   000011.100         // add -4 * b
=   000001.101100100   = 1.6953125 (intermediate result)
~      001.10110       = 1.6875 after truncation

由于b是带符号的数字,因此总是将部分和符号扩展为中间结果的宽度。当然,这也是在第二个例子的计算中完成的,但它并没有什么区别。