尽可能快地交换整数中的两位

时间:2015-02-09 23:07:13

标签: bit-manipulation

我一直在看这些有趣的面试问题。人们有一个问题,即在给定两位索引的情况下,应该编写代码以在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%。正如我在评论中所说,我对是否有任何有趣的技巧非常感兴趣。我已经看到了一些非常聪明的小动作技巧,只需几条指令即可完成相当复杂的工作。

1 个答案:

答案 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处的原始位不同(1001)时,x才等于1,因此需要切换。否则它为零,并且位保持不变(0011)。然后,我们将此切换位应用于原始位(即使用原始位对其进行异或)以获得所需的结果。