【问题标题】:log2 of an integer that is a power of 2 [duplicate]log2 是 2 的幂的整数 [重复]
【发布时间】:2017-11-02 11:24:50
【问题描述】:

假设它是 2 的幂,有没有一种有效的方法来找到一个数字的 log2。我知道有一个明显的方法,比如有一个表或

for (log2=0;x!=1;x>>=1,log2++);

但我想知道是否有更高效/优雅的方式。

【问题讨论】:

  • 你检查过数学库吗?我敢打赌有一些有效的功能
  • log2(x) 怎么样,其中 x 是您要查找 2 对数的数字?
  • 但是你可能真的只是想要来自<cmath>std::log2()。如果您可以使用分析器证明瓶颈,则只需担心尝试找到更有效的方法。
  • @RichardCritten - 但是您如何索引该查找表?

标签: c++ algorithm math logarithm


【解决方案1】:

您可以只计算前导或尾随零位的数量,因为任何精确的 2 次幂都表示为单个 1 位,而所有其他位都为 0。许多 CPU 都有执行此操作的特殊指令,编译器如因为 gcc 具有这些操作的内在函数,它们在适当的架构上被编译为单个指令。

如果您有一个高效的clz(“计数前导零”),那么log2 的实现可能如下所示:

int32_t ilog2(uint32_t x)
{
    return sizeof(uint32_t) * CHAR_BIT - clz(x) - 1;
}

(注意:ilog2(0) 返回 -1。)

当使用 gcc 或兼容 gcc 的编译器时,您可以像这样定义 clz

#define clz(x) __builtin_clz(x)

微软也有类似的东西:BitScanReverse

请注意,计数 尾随 个零(使用 ctz 指令)可能看起来更方便,但 a clz instruction is more widely available on different CPU architectures

使用clz 而不是ctz 的另一个好处是,对于非2 的幂值,您会得到floor(log2(x)),这使您的ilog2 函数比使用ctz 时更有用,仅适用于精确的 2 次幂。

另请参阅:Finding the first set bit in a binary number

【讨论】:

  • 不仅 ctz(num) 足以获取 num 中的尾随零吗?
  • __builtin_ctz 是一个更直接的选择,当然......
  • 是的,虽然(例如 ARM)并非所有 CPU 都有 ctz 指令 - 根据我的经验,clz 似乎更常见。请参阅:Find first set 维基百科条目以获得良好的摘要。
  • 对于ctz,我没有检查arm,但是在aarch64上gcc生成rbit+clz,应该不会比31-clz差多少。
  • (0 不是 2 的幂,但实际上人们经常需要处理 2 或 0 的幂)gcc 的文档说 __builtin_c[lt]z 都未定义,参数为 0。
【解决方案2】:

我没有对此进行基准测试,但它应该运行得相当快,因为​​它不需要多次迭代:

int which_power_of_2(uint64_t x) {
    uint64_t z = 0x0000000100000000ULL;
    int p = 31, d = 16;
    while (d) {
        if (x & (z-1)) {
            p -= d;
            z >>= d;
        }
        else {
            p += d;
            z <<= d;
        }
        d >>= 1;
    }
    return x ? ((x & z) ? p+1 : p) : -1;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-08
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多