二进制乘法器的C ++实现

时间:2013-04-08 12:41:31

标签: c++

我正在尝试使用32位二进制乘法器的C ++实现。我知道只有一种方法可以做到这一点

    1011   (this is 11 in decimal)      
x   1110   (this is 14 in decimal)      
   ======        
    0000   (this is 1011 x 0)       
   1011    (this is 1011 x 1, shifted one position to the left)      
  1011     (this is 1011 x 1, shifted two positions to the left)     
 1011      (this is 1011 x 1, shifted three positions to the left)   
=========    
10011010   (this is 154 in decimal). 

还有另一种方法可以做到这一点,因为我不得不对更长的二进制数进行操作,因此编码不是很麻烦吗?

4 个答案:

答案 0 :(得分:0)

您可以使用Booth的乘法算法。有关维基百科的更多信息:http://en.wikipedia.org/wiki/Booth%27s_multiplication_algorithm

答案 1 :(得分:0)

由于积分类型的隐式乘法是二进制乘法,您可以直接利用它来将数字视为基数2 8 ,2 16 或更高,而不是基数2 1

如果您假设8位数字(乘以unsigned char s),则下面的24位示例不如您在问题中发布的4位乘法复杂。

           a1 a2 a3   (this is a 3 byte value)      
       x   b1 b2 b3   (this is another 3 byte value)      
           ======        
       xx xx xx xx    (this is a x b3)       
    xx xx xx xx       (this is a x b2, shifted 8 bits to the left)      
 xx xx xx xx          (this is a x b1, shifted 16 bits to the left)
 =================    
 xx xx xx xx xx xx    (this is the result). 

您可以将上面的“字节”替换为shortlong,并相应地调整班次。

请确保将被乘数转换为足够大的类型,以便在乘法之前保持进位

答案 2 :(得分:0)

是的,您可以通过使用循环来完成此任务。 假设类型long是32位,因此long * long的结果是64位。

例如,如果您有long A蚂蚁long B,并且您想要计算a*b

首先,将结果定义为long long result = 0;。 然后检查B的每一位,如果位为1,则将A << X添加到result.Where是位的索引。 一个循环可以实现这一目标。

long long AA = A;// convernt A to AA to avoid overflow
for( int index=0;i<32;++index )
{
    if( B & 0x1 )
        result += AA;
    AA <<= 1;
    B >>= 1;
}

我希望我没有犯错,这个想法可以帮助你。

答案 3 :(得分:0)

嗯,任意精度和大数的(正确和有效)实现是非常麻烦的,并且在生产代码中使用它通常建议更好地使用经过测试的框架(例如,{{ 3}},boost等。)

但是,如果您自己实现它,我不会将数字存储为位序列,而是存储为unsigned int等机器字序列,以充分利用您的硬件ALU功能。所以每个单词都代表了一些位,你的ALU知道如何将它们相乘。

请注意,当您将数字乘以n位数(基数无关)时,您会得到一个数字为2n的数字,例如99 * 99 = 9801(基数10),0xFF * 0xFF = 0xFE01(基数16)。 因此,如果您的系统std::uintmax_tstd::uint64_t,则可以将您的号码存储为std::uint32_t的序列。乘以两位数将它们转换为std::uint64_t并乘以它们。高32位将成为下一个更高位的乘法运算的部分。 (实际上,您也可以直接乘以std::uintmax_t个变量,但获取结果的高位通常有点棘手并且涉及内联汇编以访问相应的EDX\RDX寄存器。)

有了这些知识,gmp的实现应该很简单:只需遍历数字a[i]的所有数字a,并将每个数字乘以数字b(不要)忘记传播携带)。将结果向上移动i位数,并将所有内容添加到最终结果中。

注意,该算法在原始乘法的数量方面具有二次复杂度。如果你有(非常,非常)大数字,你也可以切换到更复杂的方法,如Karatsuba甚至FFT和Schönhage-Strassen。但在这种情况下,我真的建议使用库。