通常哪种更快的解决方案,乘法或位移?
如果我想乘以10000,哪个代码会更快?
v = (v<<13) + (v<<11) + (v<<4) - (v<<8);
或
v = 10000*v;
问题的第二部分 - 如何找到进行一些乘法所需的最小次数变换? (我喜欢乘以10000,1000和100)。
答案 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)
只有一种情况,其中移位操作比*快,并且它由两个条件定义:
让我们看一点:
如果你没有处理2的幂而不是乘法和除法的执行方式略有不同:
<强>总结强>
乘法只是一条指令;在更换时 乘以一系列移位操作是多重的 说明 - &gt;第一个选项更快(即使是平行的 体系结构)
乘以2的幂与移位操作相同;编译器通常会在代码中检测到这种情况时生成一个移位。
除法是多指令;通过一系列转换来重置这一点可能会更快,但这取决于每种情况。
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