首先找到二进制数“1”

时间:2012-11-20 15:54:57

标签: c algorithm assembly x86

  

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

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

e.g。如果我有数字00000000 00000000 00000000 10000000

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

有没有比

更快的方法
int pos=0;
int number = 127; //binary from above
while ((number>>pos) > 0) { pos++; }

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

5 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:3)

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

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

这是一个对数算法。

首先,您将数字拆分为2个短路,并检查0是否为短路。如果为0,则去检查高位部分,保持偏移= 16。如果不是0,则去检查低部分,偏移= 0.您将保留短和偏移

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

接下来,将char分成2位4位,并检查相同的内容。

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

答案 2 :(得分: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(未设置位),则结果未定义!

如果输入为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(签名大小类型)

答案 3 :(得分:1)

MSVC内在函数为_BitScanForward_BitScanReverse

您可以查找他们的参数here,它们不是过于直观(您想要的值不是返回值)。

答案 4 :(得分:-2)

这几乎是最快的方法。如果你正在处理多个单词的潜力,你可以测试第一个单词然后第二个单词,然后找到最低的不是0个单词。你仍然需要改变它。