二进制定点乘法

Binary fixed point multiplication

我正在实现一个 VHDL 8 位定点乘法模块,其中 returns 一个 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 就是 link。根据这个文件,为了这个文件,这只能在做扩展乘法时完成。并且乘法的最后部分和必须取反,然后加 1 才能得到正确的数字。

为了乘法,我在程序员模式下使用了 windows' 计算器,这意味着为了乘以 8 位,我将数字放入计算器,然后得到结果并将其截断。如果它们适用于其他情况,则意味着 windows 计算器正在执行直接乘法(按应有的方式添加所有部分和,而不是反转最后的部分和)。所以,这意味着为了获得真正的结果,我应该从最终结果中减去第一个操作数,然后加上第一个操作数 inverted + 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。这些输出不是很好,但至少它们更接近我的预期。还有其他更简单的方法吗?

您的中间结果是错误的,因此截断没有按预期进行。此外,如果中间结果的四个 top-most 位在您的格式中相等,则只有在没有溢出的情况下才能截断。 您应该使用带符号的 data-types 进行正确的乘法运算。

即使你的第二个例子也是错误的。中间二进制结果 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 的二进制补码,因为 a 的 top-most 位中的 '1' 表示值 -(2^2 ) = -4。此处可以进行无溢出截断,因为中间结果的 4 top-most 位相等。

现在是第三个例子

    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是一个带符号的数字,所以总是sign-extend中间结果宽度的部分和。当然,在第二个例子的计算中也这样做了,但是没有区别。