使用Bitshifts的乘法算法

时间:2016-04-27 04:40:17

标签: c algorithm multiplication

在寻找一个有效的算法来乘以2个大数时,在论坛中遇到了以下c方法: -

...
    typedef unsigned long long ULL;

    ULL multiply (ULL a,ULL b)
    {
      ULL result = 0;
      while(a > 0)
      {
        if(a & 1)
        {
          result += b;
        }
        a >>= 1;
        b <<= 1;    
      }

      return result;
    }
...

上述算法不需要乘法指令,而只使用位移和加法运算(从而使其更快)。

检查方法是否正常,但是,我还没有完全了解它是如何工作的。解释会有所帮助。

2 个答案:

答案 0 :(得分:4)

它迭代a中的所有1位,添加b移动了适当的数量。

首先请注意,如果a11001,则可将其视为10000 + 1000 + 1,因此a * b(10000*b) + (1000*b) + (1*b)。 然后,请注意10000*b只是b << 4

每次循环时,b向左移动1以反映当前的移位量,a向右移动1,以便可以测试低阶位。在此示例中,它最终会添加b + (b << 3) + (b << 4),这只是(1*b) + (1000*b) + (10000*b)

答案 1 :(得分:1)

哇,这是一个很好的算法,和我们手工做的类似:

123*  
456=  
6*(123)+  
50*(123)+ //this means one digit shift, nice and easy  
400*(123) //this means two digits shift, nice and easy  

所以让我们做二进制文件:

101*  //b  
110=  //a  
0*(101)+    
10*(101)+ //=1*(1010) //one digit shift  
100*(101) //=1*(10100) //two digits shift  

a 向右移动以访问其第一位: if(a&amp; 1)
b 向左移动每个位置进行与上面相同的一位移位

这正是我们手工繁殖时所做的事情

我建议使用

中的 uint64_t
#include<stdint.h>

良好而清晰的编码风格:

#include<stdint.h> 
uint64_t multiply(uint64_t a, uint64_t b)
{
    uint64_t result = 0;
    while (a > 0)
    {
        if (a & 1)
        {
            result += b;
        }
        a >>= 1;
        b <<= 1;
    }
    return result;
}

int main() {
    uint64_t a = 123;
    uint64_t b = 456;
    uint64_t c = multiply(a, b);
}