得到第i位 - 是%还是更快?

Pop*_*orn 2 math performance assembly bit-manipulation bit

我想知道以下哪一个更快获得整数x的第i位,其中我从0开始:

x & (1 << i)
x >> i % 2
Run Code Online (Sandbox Code Playgroud)

也很好奇为什么一个更快.

谢谢!

Tho*_*son 8

注意

评论说,这取决于许多因素.另外,你不应该在乎.在任何真正的程序中,我不相信你会关注这种低级细节.过早优化是一种可怕的浪费时间.

而且,除非你的平等概念只是零/非零的概念,否则它们不是平等的操作.

但这是一个有趣的练习

将GCC与-O3一起使用并进行反汇编我看到:

x & (1 << i)

The first version
Dump of assembler code for function op1:
   0x0000000000000000 <+0>:     mov    %esi,%ecx
   0x0000000000000002 <+2>:     mov    $0x1,%eax
   0x0000000000000007 <+7>:     shl    %cl,%eax
   0x0000000000000009 <+9>:     and    %edi,%eax
   0x000000000000000b <+11>:    retq   
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

x >> i % 2

Dump of assembler code for function op2:
   0x0000000000000010 <+0>:     mov    %esi,%ecx
   0x0000000000000012 <+2>:     sar    %cl,%edi
   0x0000000000000014 <+4>:     mov    %edi,%edx
   0x0000000000000016 <+6>:     shr    $0x1f,%edx
   0x0000000000000019 <+9>:     lea    (%rdi,%rdx,1),%eax
   0x000000000000001c <+12>:    and    $0x1,%eax
   0x000000000000001f <+15>:    sub    %edx,%eax
   0x0000000000000021 <+17>:    retq   
Run Code Online (Sandbox Code Playgroud)

所以这是一个shift leftandVs的shift right,load effective addressand操作.在这个硬件上看起来很明显会更快,但除非你在微控制器上,看起来很明显的东西往往不那么清楚.让我们测试一下.

我做了一个循环,例如对(内联)操作的一千万次调用,并确保返回操作结果的总和,因此编译器不会全部抛弃它.

[tommd@mavlo Test]$ gcc -O3 so.c -o so
[tommd@mavlo Test]$ time ./so

real    0m0.388s
user    0m0.384s
sys     0m0.003s
[tommd@mavlo Test]$ time ./so

real    0m0.384s
user    0m0.380s
sys     0m0.003s
[tommd@mavlo Test]$ vi so.c  // I changed the function to the second one
[tommd@mavlo Test]$ gcc -O3 so.c -o so
[tommd@mavlo Test]$ time ./so

real    0m0.380s
user    0m0.377s
sys     0m0.002s
[tommd@mavlo Test]$ time ./so

real    0m0.380s
user    0m0.379s
Run Code Online (Sandbox Code Playgroud)

很糟糕 - 完全相同.现代超级缩放器处理器中有足够的硬件可以隐藏任何差异.


sta*_*lue 6

提取一点的惯用方法是

(x >> i) & 1
Run Code Online (Sandbox Code Playgroud)

这也可以类似地用于多个位,或者

x & (1 << i)
Run Code Online (Sandbox Code Playgroud)

如果你只是想测试一下.

请注意,在C中x不能为负数(最好声明为无符号),如果x长度超过int需要指定1在第二个中也长.

使用%会使读者感到困惑,并且可能会有更糟糕的性能,具体取决于编译器.