什么是最快的算法来返回2的幂的数字的幂?

时间:2011-04-17 08:27:01

标签: c++ algorithm

给定n = 2 ^ k,我怎样才能找到k假设n是32位整数,使用C / C ++按位?

7 个答案:

答案 0 :(得分:6)

GCC的__builtin_clz转换为x86 / x64上的BSR,ARM上的CLZ等,如果硬件没有实现,则模拟指令。
Visual C ++ 2005及更高版本有_BitScanReverse

使用这些功能,您可以获得k

答案 1 :(得分:5)

Wikipedia使用按位运算符编写如何执行此操作:

/**
 * Returns the floor form of binary logarithm for a 32 bit integer.
 * −1 is returned if ''n'' is 0.
 */
int floorLog2(unsigned int n) {
  if (n == 0)
    return -1;

  int pos = 0;
  if (n >= 1<<16) { n >>= 16; pos += 16; }
  if (n >= 1<< 8) { n >>=  8; pos +=  8; }
  if (n >= 1<< 4) { n >>=  4; pos +=  4; }
  if (n >= 1<< 2) { n >>=  2; pos +=  2; }
  if (n >= 1<< 1) {           pos +=  1; }
  return pos;
}

代码取自:Wikipedia on: Binary Logarithm此页面已更改原始版本,代码示例仍然可以找到她:Wikipedia on: Binary Logarithm (24 May 2011)

答案 2 :(得分:3)

好吧,您可以使用二进制指数显式存储在浮点数中的事实:

unsigned log2(unsigned x)
{
    float f = x;
    memcpy(&x, &f, sizeof x);
    return (x >> 23) - 127;
}

我不知道这有多快,而且它肯定不是最便携的解决方案,但我发现它非常有趣。

只是为了好玩,这是一个完全不同的,相对简单的解决方案:

unsigned log2(unsigned x)
{
    unsigned exp = 0;
    for (; ;)
    {
        switch (x)
        {
            case 128: ++exp;
            case 64: ++exp;
            case 32: ++exp;
            case 16: ++exp;
            case 8: ++exp;
            case 4: ++exp;
            case 2: ++exp;
            case 1: return exp;
            case 0: throw "illegal input detected";
        }
        x >>= 8;
        exp += 8;
    }
}

这是一个完全展开的解决方案:

#define CASE(exp) case (1 << (exp)) : return (exp);

unsigned log2(unsigned x)
{
    switch (x)
    {
        CASE(31) CASE(30) CASE(29) CASE(28)
        CASE(27) CASE(26) CASE(25) CASE(24)
        CASE(23) CASE(22) CASE(21) CASE(20)
        CASE(19) CASE(18) CASE(17) CASE(16)
        CASE(15) CASE(14) CASE(13) CASE(12)
        CASE(11) CASE(10) CASE( 9) CASE( 8)
        CASE( 7) CASE( 6) CASE( 5) CASE( 4)
        CASE( 3) CASE( 2) CASE( 1) CASE( 0)
        default: throw "illegal input";
    }
}

答案 3 :(得分:2)

继续右移n值直到你得到1.count所需的右移数量。

答案 4 :(得分:1)

对于便携式解决方案(不依赖于特定于实现的东西),您可以使用二进制印章,这可能是不涉及非便携式东西的最有效方式之一。例如,假设您的整数是8位:

// Given n = 2^k, k >= 0, returns k.

unsigned int getK (unsigned int n) {
    if (n <= 8) {
        if (n <= 2) {
            if (n == 1) return 0;
            return 1;
        }
        if (n == 4) return 2;
        return 3;
    }
    if (n <= 32) {
        if (n == 16) return 4;
        return 5;
    }
    if (n == 64) return 6;
    return 7;
}

随着整数大小的增加,这有点笨拙,但你只需要写一次: - )

答案 5 :(得分:0)

给定:0 <= n <= 2**32表示0 <= k <= 32,k可以用字节表示。 2 ** 32字节的RAM一般不会过分,因此最快的计算方法可能是简单的表查找。

答案 6 :(得分:0)

如果您使用GCC,我想这是最快的方式:

int ilog2(int value) {
 return 31 - __builtin_clz(value);
}

其中__builtin_clz是优化的GCC内置函数。