2016-01-26 163 views
2

我正在实现一个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) 

到目前为止everythng工作正常。问题出现在我试图乘以两个负数的情况下。根据我所知道的(除非我错了): - 将两个数相乘将得到两倍分辨率的结果(将两个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'calculator,这意味着为了乘以8位,我把数字放到计算器中,然后得到结果并截断它。如果他们为其他情况工作,则意味着Windows计算器正在进行直接乘法(将所有部分和相加,而不是反转最后的部分和)。因此,这意味着,为了获得真实的结果,我应该从最后的结果。减去第一个操作数,然后添加倒第一个操作数+ 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。这些产出并不是很好,但至少它们更接近我的预期。有没有其他方法可以以更简单的方式实现此目的?

+0

无符号或无符号您必须允许结果大小的两倍或小一大。在十进制中1000 * 1000 = 1000000可以与9999接近,但很容易看出您必须查看最高有效数字的功率,并且只有这两个数字的结果在1的范围内确定结果的大小2^7 * 2^7 = 2 * 14 8位数的乘法将需要15或16位结果,或者只是尝试0xFF * 0xFF,您将得到0xFE01。如果msbits是例如2^7 * 2^0 = 2^7那么你需要一个8或9位数的答案,在这种情况下8 0xFF * 0x01 = 0xFF。 –

+0

@RyanVincent对不起,花了我很长的时间来回答。我正在做我的平行研究并张贴我的结果。无需检测并处理溢出。我知道通过忽略这些标志来做到这一点是可行的,但我想知道是否有其他方式可以做到而不忽视它们。根据我的研究,有但是更难。我想我必须在if语句中做。如果操作数[7] ='1'且操作数2 [7] ='1',那么输入到乘法器的两个位都接收到'0',如果它们不同,则放入整个操作数。这很糟糕..我认为 – morcillo

+0

@dwelch我知道这一点。但是我知道我想应用这个特定的系统永远不会输出高于3且低于-4的结果,这就是我为什么要截断的原因。我知道结果的数字可以用8位数字表示,三位在点之前,5位在点之后。我也有两个系统来测试。其中一个将永远不会乘以两个负面投入,而另一个会。我知道我的一个系统会以这种方式工作。另一个不会。这就是为什么我想解决这个问题。我很久以前测试了截断,它为第一个系统工作(工作“完美”)。 – morcillo

回答

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二进制补码的最后部分总和,因为a最高位中的'1'表示值 - (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作为是有符号数,人们总是符号扩展部分和所述中间结果的宽度。当然,这也是在第二个例子的计算中完成的,但是这并没有什么不同。

+0

好的。我知道我的思维方式有很大的可能性。 BUUUT,我测试了许多值(包括正值,负值和负值)。当这两个数字都是负数时,我只遇到了问题,其他所有测试都起作用(截断后)。我明白你告诉我的是什么,但在我的情况下,所有乘法在截断后都是正确的(除了两个都是负数),我知道其中一个操作数将从0变化到1,而另一个不会高于3。我的测试工作。这是巧合吗?我真的很喜欢你的答案。 – morcillo

+0

感谢您花时间回答我的问题。 – morcillo

+0

@morcillo你喜欢我的回答,但没有投票赞成吗? –