如何确定两个幂的幂所需的正确位移数?

时间:2012-03-07 09:29:11

标签: c# math bit-manipulation

我有一个接收两个值的函数。

我需要将它转换为枚举范围(0,1,2,3等),然后将其转换回两个范围的幂。

 0         1
 1         2
 2         4
 3         8
 4        16
 5        32
 6        64
 7       128
 8       256
 9       512
10      1024
... and so on.

如果我的函数收到1024的值,我需要将其转换为10.在C#中执行此操作的最佳方法是什么?我应该在循环中继续除以2并计算迭代次数吗?

我知道我可以用(1<<< 10)

3 个答案:

答案 0 :(得分:5)

只需使用基数2的对数:

Math.Log(/* your number */, 2)

例如,Math.Log(1024, 2)返回10.

更新

这是一个相当强大的版本,用于检查传入的数字是否为2的幂:

public static int Log2(uint number)
{
  var isPowerOfTwo = number > 0 && (number & (number - 1)) == 0;
  if (!isPowerOfTwo)
  {
    throw new ArgumentException("Not a power of two", "number");
  }

  return (int)Math.Log(number, 2);
}

检查number是2的幂是取自http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2

从该页面开始,有更多技巧可以在该页面上找到整数的log2: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious

答案 1 :(得分:2)

当你的CPU没有位扫描指令或者你无法访问该指令时,这是最快的算法:

unsigned int v;  // find the number of trailing zeros in 32-bit v 
int r;           // result goes here
static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];

如果你想知道它是如何工作的,请参见this paper,基本上,它只是一个完美的哈希。

答案 2 :(得分:0)

使用_BitScanForward。它就是这样做的。