什么算法能最快地返回一个数的幂,也就是2的幂

What is the fastest algorithm to return the power of a number which is a power of 2?

本文关键字:一个 的幂 也就是 算法 返回 什么      更新时间:2023-10-16

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

GCC有__builtin_clz,它在x86/x64上转换为BSR,在ARM上转换为CLZ等,如果硬件不实现它,它会模拟指令。
Visual c++ 2005及以上版本有_BitScanReverse

使用这些函数,您可以得到k

维基百科写了如何使用位运算符:

/**
 * 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;
}

代码取自:维基百科上:二进制对数此页已被更改,原始版本的代码样本仍然可以找到她:维基百科上:二进制对数(2011年5月24日)

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

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";
    }
}

继续右移n的值,直到你得到get 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;
}

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

给定0 <= n <= 2**32,即0 <= k <= 32和k可以用一个字节表示。2**32字节的内存通常不会太大,所以最快的计算方法可能是简单的表查找。

如果你使用GCC,我猜这是最快的方法:

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

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