5

可能重复:
用于计数位或找到最右边|最左边的有效位运算

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

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

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

有没有比这更快的方法

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

?

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

4

5 回答 5

5

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

于 2012-11-20T15:59:32.023 回答
3

您正在寻找 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(未设置位),则结果未定义!

pos如果输入为 0 ,下面是一个将预定义常量放入的版本:

#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_tssize_t(有符号大小类型)

于 2012-11-20T16:17:46.810 回答
3

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

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

这是一个对数算法。

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

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

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

您将进行最大日志 32 * 2 操作。

于 2012-11-20T16:09:51.197 回答
1

MSVC 内在函数是_BitScanForward_BitScanReverse

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

于 2012-11-20T16:06:14.073 回答
-2

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

于 2012-11-20T15:59:30.363 回答