快速确定64位中最右边第n位的方法

时间:2010-03-04 07:51:24

标签: c++

我尝试确定最右边的第n位设置

if (value & (1 << 0)) { return 0; }
if (value & (1 << 1)) { return 1; }
if (value & (1 << 2)) { return 2; }
...
if (value & (1 << 63)) { return 63; }

如果比较需要进行64次。有没有更快的方法?

7 个答案:

答案 0 :(得分:5)

这有一个小技巧:

value & -value

这使用负数的二进制补码整数表示。

编辑:这并不完全给出问题中给出的确切结果。其余的可以用一个小的查找表来完成。

答案 1 :(得分:5)

如果您使用的是GCC,请使用__builtin_ctz__builtin_ffs功能。 (http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fffs-2894

如果您使用的是MSVC,请使用_BitScanForward功能。请参阅How to use MSVC intrinsics to get the equivalent of this GCC code?

在POSIX中还有一个ffs函数。 (http://linux.die.net/man/3/ffs

答案 2 :(得分:2)

您可以使用循环:

unsigned int value;
unsigned int temp_value;
const unsigned int BITS_IN_INT = sizeof(int) / CHAR_BIT;
unsigned int index = 0;

// Make a copy of the value, to alter.
temp_value = value;
for (index = 0; index < BITS_IN_INT; ++index)
{
    if (temp_value & 1)
    {
        break;
    }
    temp_value >>= 1;
}
return index;

if语句提议相比,它占用的代码空间更少,具有类似的功能。

答案 3 :(得分:1)

如果您的编译器支持它们,KennyTM的建议很好。否则,您可以使用二进制搜索加速它,例如:

int result = 0;
if (!(value & 0xffffffff)) {
    result += 32;
    value >>= 32;
}

if (!(value & 0xffff)) {
    result += 16;
    value >>= 16;
}

等等。这将进行6次比较(一般来说,log(N)比较,而线性搜索则为N)。

答案 4 :(得分:1)

b = n & (-n)      // finds the bit
b -= 1;           // this gives 1's to the right
b--;              // this gets us just the trailing 1's that need counting
b = (b & 0x5555555555555555) + ((b>>1) & 0x5555555555555555);  // 2 bit sums of 1 bit numbers
b = (b & 0x3333333333333333) + ((b>>2) & 0x3333333333333333);  // 4 bit sums of 2 bit numbers
b = (b & 0x0f0f0f0f0f0f0f0f) + ((b>>4) & 0x0f0f0f0f0f0f0f0f);  // 8 bit sums of 4 bit numbers
b = (b & 0x00ff00ff00ff00ff) + ((b>>8) & 0x00ff00ff00ff00ff);  // 16 bit sums of 8 bit numbers
b = (b & 0x0000ffff0000ffff) + ((b>>16) & 0x0000ffff0000ffff); // 32 bit sums of 16 bit numbers
b = (b & 0x00000000ffffffff) + ((b>>32) & 0x00000000ffffffff); // sum of 32 bit numbers
b &= 63; // otherwise I think an input of 0 would produce 64 for a result.

当然是在C语言中。

答案 5 :(得分:0)

这是利用逻辑AND操作和条件指令执行或指令管道的短路的另一种方法。

unsigned int value;

unsigned int temp_value = value;
bool bit_found = false;
unsigned int index = 0;

bit_found = !bit_found && ((temp_value & (1 << index++)); // bit 0
bit_found = !bit_found && ((temp_value & (1 << index++)); // bit 1
bit_found = !bit_found && ((temp_value & (1 << index++)); // bit 2
bit_found = !bit_found && ((temp_value & (1 << index++)); // bit 3
//...
bit_found = !bit_found && ((temp_value & (1 << index++)); // bit 64
return index - 1; // The -1 may not be necessary depending on the starting bit number.

此方法的优点是没有分支,并且指令管道不受干扰。这在执行条件执行指令的处理器上非常快。

答案 6 :(得分:-1)

适用于Visual C ++ 6

int toErrorCodeBit(__int64 value) {
    const int low_double_word = value;
    int result = 0;

    __asm
    {
        bsf eax, low_double_word
        jz low_double_value_0
        mov result, eax
    }
    return result;

low_double_value_0:    
    const int upper_double_word = value >> 32;

    __asm
    {
        bsf eax, upper_double_word
        mov result, eax
    }
    result += 32;
    return result;
}