我想知道以下哪一个更快获得整数x的第i位,其中我从0开始:
x & (1 << i)
x >> i % 2
也很好奇为什么一个人更快。
谢谢!
答案 0 :(得分: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.
和
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
这是shift left
和and
与shift right
,load effective address
和and
操作的对比。在这个硬件上看起来很明显会更快,但除非你在微控制器上,看起来很明显的东西往往不那么清楚。让我们测试一下。
我做了一个类似于(内联)操作的一千万次调用的循环,并确保返回操作结果的总和,这样编译器就不会全部抛弃它。
[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
好糟糟糕 - 完全相同。现代超级缩放器处理器中有足够的硬件来隐藏任何差异。
答案 1 :(得分:6)
提取位的惯用方法是
(x >> i) & 1
也可以类似地用于多个位,或
x & (1 << i)
如果您只是想测试一个位。
请注意,在C x
中不能为负(最好声明为无符号),如果x
长于int
,则需要指定1也是第二个。
使用%
会使读者感到困惑,并且可能会有更糟糕的性能,具体取决于编译器。