变速或倍增更快,为什么?

时间:2014-02-27 12:38:12

标签: c++ bit-shift

通常哪种更快的解决方案,乘法或位移?

如果我想乘以10000,哪个代码会更快?

v = (v<<13) + (v<<11) + (v<<4) - (v<<8);

v = 10000*v;

问题的第二部分 - 如何找到进行一些乘法所需的最小次数变换? (我喜欢乘以10000,1000和100)。

4 个答案:

答案 0 :(得分:4)

这实际上取决于处理器的体系结构,以及您正在使用的编译器。

但您可以简单地查看每个选项的拆卸,并亲眼看看。

以下是我使用Pentium的Visual-Studio 2010编译器:

int v2 = (v<<13) + (v<<11) + (v<<4) - (v<<8);
mov         eax,dword ptr [v]  
shl         eax,0Dh  
mov         ecx,dword ptr [v]  
shl         ecx,0Bh  
add         eax,ecx  
mov         edx,dword ptr [v]  
shl         edx,4  
add         eax,edx  
mov         ecx,dword ptr [v]  
shl         ecx,8  
sub         eax,ecx  
mov         dword ptr [v2],eax  

int v2 = 10000*v;
mov         eax,dword ptr [v]  
imul        eax,eax,2710h  
mov         dword ptr [v2],eax  

所以看来第二种选择在我的情况下更快。

顺便说一下,如果启用优化(我的已禁用),您可能会得到不同的结果......

答案 1 :(得分:2)

对第一个问题:不要打扰。编译器会更好地了解并根据相应的目标硬件对其进行优化。

关于第二个问题:查看二进制表示:

例如:bin(10000)= 0b10011100010000:

 1  0  0  1  1  1  0  0  0  1  0  0  0  0
13 12 11 10  9  8  7  6  5  4  3  2  1  0

所以你必须移动13,10,9,8和4.如果你想快速连续(通过减去你的问题)你需要至少三个连续的,以获得任何东西。

但是,再次让编译器执行此操作。这是他的工作。

答案 2 :(得分:1)

只有一种情况,其中移位操作比*快,并且它由两个条件定义:

  1. 操作的值为2
  2. 当您乘以小数时 - >分裂。
  3. 让我们看一点:

    • 乘法/除法,移位操作由HW中的单元完成 建筑;通常你有变速器,乘数/分频器 执行这些操作但每个操作都由a执行 Arithmeric Locgic Unit内的不同寄存器集。
    • 乘以2的幂乘以等于a left_shift / right_shift operation
    • 如果你没有处理2的幂而不是乘法和除法的执行方式略有不同:

      • 乘法由HW(ALU单元)在单个指令中执行(取决于数据类型,但不要使事情过于复杂)
      • 分割作为连续减法循环执行 - &gt;不止一条指令

    <强>总结

    1. 乘法只是一条指令;在更换时 乘以一系列移位操作是多重的 说明 - &gt;第一个选项更快(即使是平行的 体系结构)

    2. 乘以2的幂与移位操作相同;编译器通常会在代码中检测到这种情况时生成一个移位。

    3. 除法是多指令;通过一系列转换来重置这一点可能会更快,但这取决于每种情况。

    4. 2的幂除法是多个操作,可以用单个right_shift操作替换;一个聪明的编译器会 自动执行此操作

答案 3 :(得分:1)

较旧的Microsoft C编译器使用lea(加载有效地址)优化了移位序列,允许5的倍数:

        lea     eax, DWORD PTR [eax+eax*4]  ;eax = v*5
        lea     ecx, DWORD PTR [eax+eax*4]  ;ecx = v*25
        lea     edx, DWORD PTR [ecx+ecx*4]  ;edx = v*125
        lea     eax, DWORD PTR [edx+edx*4]  ;eax = v*625
        shl     eax, 4                      ;eax = v*10000
在英特尔2600K 3.4ghz的系统上,

乘法(有符号或无符号)仍然更快。 Visual Studio 2005和2012乘以v * 10256,然后减去(v <&lt; 8)。 Shift和加/减序列比上面的lea方法慢:

        shl     eax,4      ;ecx = v*(16)
        mov     ecx,eax
        shl     eax,4      ;ecx = v*(16-256)
        sub     ecx,eax
        shl     eax,3      ;ecx = v*(16-256+2048)
        add     ecx,eax
        shl     eax,2      ;eax = v*(16-256+2048+8192) = v*(10000)
        add     eax,ecx