如何更快地进行这种按位操作?

时间:2015-12-01 18:10:41

标签: c optimization bitwise-operators

代码非常简单。

int foo(int a, int b, int c, int d, int e, int f, int g)
{    
    int r = (1 << a) | (1 << b) | (1 << c) | (1 << d) | (1 << e ) | (1 << f) | (1 << g);
    return r;
}

假设所有参数都不大于30。

它似乎是一个非常原始的函数,但在使用“-Ofast”标志进行编译后,它仍需要28条指令来计算r。

是否有替代代码可以使这些按位运算更快?

3 个答案:

答案 0 :(得分:5)

28条指令相当快。 考虑一下你在这做什么。你有:

  • 7班次操作
  • 6 OR操作
  • 1个内存分配操作

这已经需要至少14条指令。现在还有其他必要的指令,例如存储中间结果和将操作数加载到寄存器中。

如果您想进行更深入的分析,请发布程序集输出。

修改:现在可以优化您的算法。

可能能够通过牺牲一些内存来获得更快的速度。预先计算以32位值设置的每个可能位的值,例如,类似的东西:int bit2value[32]={1,2,4,8,16,32,64,...};在您的函数中,您可以通过查找预先计算的映射替换它们而不是执行移位操作:int r = bit2value[a] | bit2value[b] | bit2value[c]...;理论上这可以节省一些中间存储操作的需要。

答案 1 :(得分:0)

使用 Visual Studio 2015 (32位,针对空间进行了优化),以下代码会生成21而不是24指令:

typedef struct container
{
    int a, b, c, d, e, f, g;
} CONTAINER;

int foo2(CONTAINER *ct)
{
    int r = (1 << ct->a) | (1 << ct->b) | (1 << ct->c) | (1 << ct->d) | (1 << ct->e) | (1 << ct->f) | (1 << ct->g);
    return r;
}

汇编代码(21而不是20条指令,抱歉!):

1   push    esi
2   mov edx, ecx
3   xor esi, esi
4   inc esi
5   mov ecx, DWORD PTR [edx+24]
6   mov eax, DWORD PTR [edx+20]
7   shl esi, cl
8   mov ecx, DWORD PTR [edx+8]
9   bts esi, eax
10  mov eax, DWORD PTR [edx+16]
11  bts esi, eax
12  mov eax, DWORD PTR [edx+12]
13  bts esi, eax
14  bts esi, ecx
15  mov ecx, DWORD PTR [edx+4]
16  bts esi, ecx
17  mov ecx, DWORD PTR [edx]
18  bts esi, ecx
19  mov eax, esi
20  pop esi
21  ret 0

答案 2 :(得分:0)

对于您需要的每个参数:

mov cl, argument
mov edx, 1
shl edx, cl
or eax, edx

我相信你的功能有7个参数?最高g? 27(4 * 7 - 1)尽可能低,因为你可以直接在eax计算第一个参数的移位结果。您不能 将每个参数加载到寄存器中,因为指令不直接在内存上运行。每次不设置为1时,您无法移动1。显然,你不能没有转换指令或or