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

C++ 确定64位中最右边的第n位集的快速方法,c++,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; } if(value&(1有一个小技巧: value & -value 它使用负数的

我试图确定最右边的第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; }

if(value&(1有一个小技巧:

value & -value
它使用负数的两个补码整数表示


编辑:这并没有给出问题中给出的确切结果。剩下的可以通过一个小的查找表来完成。

如果您使用的是GCC,请使用
\uuuuuuu内置\uCTZ
\uuuuuu内置ffs
函数。()

如果您使用的是MSVC,请使用
\u BitScanForward
功能。请参阅

在POSIX中还有一个代码> FFS函数。()

P>为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;
}

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

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

if (!(value & 0xffff)) {
    result += 16;
    value >>= 16;
}
以此类推。这将进行6次比较(通常,对数(N)比较,而线性搜索为N)。

您可以使用循环:

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;
无符号整数值;
无符号int-temp_值;
常量无符号整数位\u IN\u int=sizeof(int)/CHAR\u位;
无符号整数索引=0;
//复制该值,以进行更改。
温度值=温度值;
for(索引=0;索引>=1;
}
收益指数;

这比具有类似功能的
if
语句提案占用更少的代码空间。

这是另一种利用逻辑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.
无符号整数值;
无符号int temp_值=值;
bool bit_found=false;
无符号整数索引=0;
已找到位=!已找到位(&)(临时值(&)(1
b=n&(-n)//查找位
b-=1;//这给了右边1
b--;//这只得到需要计数的尾随1
b=(b&0x5555)+(b>>1&0x5555);//1位数字的2位和
b=(b&0x3333)+(b>>2&0x3333);//2位数字的4位和
b=(b&0x0f0f)+(b>>4&0x0f0f);//4位数字的8位和
b=(b&0x00FF00FF00FF)+(b>>8&0x00FF00FF00FF);//8位数字的16位和
b=(b&0x0000ffff0000ffff)+(b>>16&0x0000ffff0000ffff);//16位数字的32位和
b=(b&0x00000000FFFFFF)+(b>>32&0x00000000FFFFFF);//32位数字之和
b&=63;//否则,我认为输入0将产生64个结果。

这当然是C语言。

Duplicate:Then?如果value=11100,value&-value=00100。如何返回唯一的“1”位置?数组表查找?@Yan:是的,它可以是包含64个条目的查找表。您可能还想查看KennyTM提出的ctz建议。我想这会更快。您如何准确地查找它?这些值是0f 2.预定义的哈希映射?您的哈希函数到底是什么?它比64个右移更有效吗?它需要O(1)内存,还是使用表查找本身?现在,您当然可以(例如)使用三个移位/掩码/测试来隔离包含1的字节,然后使用256个条目的表(或使用不同的时空权衡),但我不会将其称为包含64个条目的查找表。(当然,如果沿着该路径,您可以直接解决原始问题。无需先关闭非最高有效位。)@ari:散列函数可以是一个小整数的模运算。我认为它可能比64个右移快,但你应该测量它以确定它。+1:这些看起来很好的建议,只要它是编译器特定的。“没有分支”?每个
&&
都是一个分支!-编辑:好的,这可以编译为setcc,但它仍然比其他解决方案长。请注意,这不是完全可移植的-第一行假设负整数的补码表示形式为2。@Mike.IIRC从技术上讲,您是正确的。但是您知道有任何C编译器不这样做吗?I如果有,则使用-n=(~n)+1.这取决于目标处理器,而不是编译器。2的补码目前几乎是通用的,但一些Unisys大型机显然使用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.