【问题标题】:Optimized method to find log2 using C [duplicate]使用 C 查找 log2 的优化方法 [重复]
【发布时间】:2018-03-07 21:02:26
【问题描述】:

我正在寻找一种有效的方法(最好使用少量按位运算),它返回左移计数或将方程求解为:

为给定的 y 找到 x,其中 y=2^x

例如 (1 4 的左移量。另外,我不是在寻找涉及 looplog 方法的方法,例如:

unsigned int count_shift(unsigned int shifted)
{
    unsigned int count = 0;

    for (count = 0; shifted != 0x1; count++)
    {
        shifted /= 2;   
    }
    return count;
}

干杯!

【问题讨论】:

  • 内存空间效率高,还是寄存器使用率高?
  • 您可能已经被 C# 引用推迟了。但是来自@LưuVĩnhPhúc 的第二个链接在 C 中给出了一个很好且非常紧凑的答案:stackoverflow.com/a/24748784/4213662
  • @MartinJames 代码在嵌入式平台上实现 ISR(中断服务例程),从而减少 CPU 周期
  • @Bathsheba 这就是我在中断处理程序中所做的,是的。我想您可以快速找出哪个字节中有一个,然后查找,或者只是通过进位旋转。

标签: c algorithm arm


【解决方案1】:

如果保证数字是 2 的幂,即y == 1 << x,则可以使用 256 字节的查找表和四次查找:

static unsigned char lookup[256] = {
    [0x01]=1, [0x02]=2, [0x04]=3, [0x08]=4, [0x10]=5, [0x20]=6, [0x40]=7, [0x80]=8
};

unsigned log2uint(unsigned y) {
    unsigned res = lookup[(y >>  0) & 0xFF];
    if (res) return res +  0 - 1;
    res = lookup[(y >>  8) & 0xFF];
    if (res) return res +  8 - 1;
    res = lookup[(y >> 16) & 0xFF];
    if (res) return res + 16 - 1;
    res = lookup[(y >> 24) & 0xFF];
    if (res) return res + 24 - 1;
    return 0;
}

Demo 1

如果您不介意特定于供应商的功能,gcc 提供了 __builtin_ctz 函数,该函数返回尾随零的数量,这与您在 y == 1 << x (Demo 2) 时获得的返回值相匹配

【讨论】:

    【解决方案2】:

    除非您使用查找表1,否则已知最快的方法是 O(N):

    unsigned int count = 0;
    while (shifted >>= 1){
      ++count;
    }
    

    1explog 在某些芯片上是如何评估的 - 牛顿拉夫森型算法,带有定义某些功能点的查找表。

    【讨论】:

    • 好吧..如果 N 是位数,则可以使用二进制搜索在 O(log N) 中完成。对于小 Ns 而言,这并不值得
    • @EugeneSh.:我会赞成这样写的答案;我从未见过这样的成功解决方案。不确定它是否会更快,即使是 128 位。
    • 不会的。我只是反对 已知最快的方法是 O(N) 的断言。
    • 开销不会将对数复杂度变为线性
    • 我同意并在第一条评论中说明了这一点。对于任何标准类型,我认为 N 都很小:)
    猜你喜欢
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多