左移仅是数字的一部分

时间:2010-12-09 11:54:11

标签: c optimization assembly x86

我需要找到以下C代码的最快等价。

int d = 1 << x; /* d=pow(2,x) */
int j = 2*d*(i / d) + (i % d);

我的想法是将左上32位x移位 例如,以下i,x = 5:
1010 1010 1010 1010
将成为:
0101 0101 010 0 1010
是否有汇编命令?如何快速执行此操作?

5 个答案:

答案 0 :(得分:9)

分歧很慢:

int m = (1 << x) - 1;
int j = (i << 1) - (i & m);

<强>更新

或者可能更快:

int j = i + (i & (~0 << x));

答案 1 :(得分:5)

x86 32位汇编(AT&amp; T语法):

/* int MaskedShiftByOne(int val, int lowest_bit_to_shift) */
mov 8(%esp), %ecx
mov $1, %eax
shl %ecx, %eax            ; does 1 << lowest_bit_to_shift
mov 4(%esp), %ecx
dec %eax                  ; (1 << ...) - 1 == 0xf..f (lower bitmask)
mov %eax, %edx
not %edx                  ; complement - higher mask
and %ecx, %edx            ; higher bits
and %ecx, %eax            ; lower bits
lea (%eax, %edx, 2), %eax ; low + 2 * high
ret

这应该适用于Linux和Windows。

编辑:i + (i & (~0 << x))更短:

mov 4(%esp), %ecx
mov $-1, %eax
mov 8(%esp), %edx
shl %edx, %eax
and %ecx, %eax
add %ecx, %eax
ret

士气:不要从装配开始。如果你确实需要它,请反汇编高度优化的编译器输出...

答案 2 :(得分:4)

向左移动一个上x位。

unsigned i = 0xAAAAu;
int x = 5;
i = (i & ((1 << x) - 1)) | ((i & ~((1 << x) - 1)) << 1); // 0x1554A;

一些解释:

(1 << x) - 1使掩码为零32 - x位。

~((1 << x) - 1)使掩码为零x位。

在归零后,我们将上部和or移到一起。

Codepad上试试。

答案 3 :(得分:3)

int m = (1 << x) - 1;
int j = ((i & ~m) << 1) | (i & m);

没有汇编命令可以执行您想要的操作,但我提供的解决方案更快,因为它避免了划分。

答案 4 :(得分:1)

Intel语法:

mov ecx,[esp+4]      ;ecx = x
mov eax,[esp+8]      ;eax = i

ror eax,cl
inc cl
clc
rcl eax,cl
ret

道德:高度优化的编译器输出......不是。