我一直在看这些有趣的面试问题。人们有一个问题,即在给定两位索引的情况下,应该编写代码以在64位整数中翻转两位。在玩了一段时间之后,我想出了以下代码,这比教科书中给出的解决方案更快,因为它没有任何分支:
uint64_t swapbits(uint64_t n, size_t i, size_t j)
{
// extract ith and jth bit
uint64_t bi = ((uint64_t) 0x1 << i) & n;
uint64_t bj = ((uint64_t) 0x1 << j) & n;
// clear ith and jth bit in n
n ^= bi | bj;
n ^= (bi >> i) << j;
n ^= (bj >> j) << i;
return n;
}
我的问题基本上如下:有更快的方法吗?
编辑:这是另一个实现作为参考:
uint64_t swapbits(uint64_t x, size_t i, size_t j)
{
if(((x >> i) & 1) != ((x >> j) & 1)) {
x ^= (1L << i) | (1L << j);
}
return x;
}
使用编译器优化,后者在Core i7 4770上的速度慢了约35%。正如我在评论中所说,我对是否有任何有趣的技巧非常感兴趣。我已经看到了一些非常聪明的小动作技巧,只需几条指令即可完成相当复杂的工作。
答案 0 :(得分:1)
这是一个只使用7次操作的解决方案。请注意,即使i == j
。
uint64_t swapbits(uint64_t n, size_t i, size_t j)
{
uint64_t x = ((n >> i) ^ (n >> j)) & 1; // x = 1 bit "toggle" flag
return n ^ ((x << i) | (x << j)); // apply toggle to bits i and j
}
说明:仅当索引i和j处的原始位不同(10
或01
)时,x才等于1,因此需要切换。否则它为零,并且位保持不变(00
或11
)。然后,我们将此切换位应用于原始位(即使用原始位对其进行异或)以获得所需的结果。