【问题标题】:Find first "1" in binary number [duplicate]在二进制数中找到第一个“1”[重复]
【发布时间】:2012-11-20 15:54:57
【问题描述】:

可能重复:
Efficient bitwise operations for counting bits or find the right|left most ones

有没有快速找到(32 位)二进制数中的第一个 1 的方法?

例如如果我有数字 00000000 00000000 00000000 10000000

我想计算值“7”(或“24”,如果从另一侧读取),因为数字中的第一个零存储在右侧的第 7 位中。

有没有比这个更快的方法

int pos=0;
int number = 127; //binary from above
while ((number>>pos) > 0) { pos++; }

?

也许是特定的 x86 汇编指令?

【问题讨论】:

  • 你假设只有一个“1”吗?
  • 从左起第一个(从 MS 位开始)或从右起第一个 1(从 LS 位开始)?
  • 为什么你认为你需要优化这个?你会调用它数百万次吗?
  • 使用此处描述的方法之一:Bit Twiddeling Hacks
  • @SteveWellens 我不了解 OP,但实际上我有代码在运行数小时的科学代码中每隔约 300 个 CPU 周期调用一次 bsr。所以考虑这个是有道理的。

标签: c algorithm assembly x86


【解决方案1】:

使用 gcc,您可以使用 __builtin_ctz__builtin_clzctz 给出尾随 0 位的数量,clz 给出前导 0 位的数量。

【讨论】:

  • 怎么用?
  • @TonyTannous 调用函数即可。声明为int __builtin_clz (unsigned int x)
【解决方案2】:

您正在寻找x86的位扫描指令

__inline__ size_t bsf(size_t input) {
    size_t pos;
    __asm__ ("bsf %1, %0" : "=r" (pos) : "rm" (input));
    return pos;
}

如果使用内联 asm,请确保 posinput 是相同的存储类(2、4 或 8 字节整数类型)。这个内联函数应该没问题。

大多数编译器都有使用这条指令的内在函数,但我知道只有 MSVC 有直接指令。

对于最高位设置,请改用bsr 指令,语法相同。

注意:如果输入为 0(未设置位),则结果未定义!

这是一个版本,如果输入为 0,则将预定义常量放入 pos

#define BIT_SCAN_IFZERO 0

__inline__ size_t bsf(size_t input) {
    size_t pos, ifzero = BIT_SCAN_IFZERO;
    __asm__ ( "bsf %1, %0\n\t"
              "cmovz %2, %0"
            : "=r" (pos)
            : "rm" (input)
            , "rm" (ifzero));
    return pos;
}

BIT_SCAN_IFZERO 定义为您喜欢的任何内容。如果你想要一个负数,那么将size_t 更改为ssize_t(有符号大小类型)

【讨论】:

  • 当输入为 0 时它是未定义的这一事实非常令人不舒服。我必须在代码周围引入分支来检查这种可能性。有没有办法解决这个问题?
  • @TravisG 添加了一个将预定义常量放入的版本。这是一个有条件的移动,不需要分支。
【解决方案3】:

是的,有一种更快的方法——不使用宏。

使用您的方法,您最多可以拥有 32*2 个操作。

这是一个对数算法。

首先,您将数字分成 2 个短裤,并检查较低的短裤是否为 0。如果为 0,你去检查高位部分,保持 offset=16。如果不是 0,请检查低位,偏移量 = 0。您将保持短路和偏移量

接下来,将剩余部分分成 2 个字符,然后继续进行相同的操作。您将保留一个字符和一个偏移量。

接下来,将 char 分成 4 位的 2 部分,并检查是否相同。

您将进行最多记录 32 * 2 次操作。

【讨论】:

  • 虽然这是真的,但根据他问题的最后一行,我严重怀疑这是否是他正在寻找的答案。
【解决方案4】:

MSVC 内部函数是 _BitScanForward_BitScanReverse

你可以查看他们的参数here,它们并不太直观(你想要的值不是返回值)。

【讨论】:

    【解决方案5】:

    这几乎是最快的方法。如果您我们正在处理多个单词的可能性,您可以测试第一个单词然后是第二个单词,依此类推并找到最低的非 0 单词。不过,你仍然需要改变它。

    【讨论】:

    • 不,这肯定不是“最快的方法”。
    猜你喜欢
    • 2014-03-04
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 2020-08-10
    • 2017-09-22
    相关资源
    最近更新 更多