(编辑)
隔离最低设置位x &= (-x),然后查看How to find the position of the only-set-bit in a 64-bit value using bit manipulation efficiently?,它正在检查这个确切的问题(尽管有标题)。
下面的答案稍微笼统一些。
通过消除表查找,可以通过 de Bruijn 位扫描节省几个延迟周期。
uint64_t ByteIndexOfLowestSetBit(uint64_t val) {
assert(val != 0);
const uint64_t m = UINT64_C(0x0101010101010101);
return ((((val - 1) ^ val) & (m - 1)) * m) >> 56;
}
使用尾随位操作来获得覆盖最低设置位及以下的掩码。
将掩码覆盖的每个字节设置为1。通过对它们进行水平前缀求和来计算我们有多少 1 字节。我们现在已经在 u64 字的最高有效字节中放置了一个基于 1 的字节索引。将计数移到底部并减去 1 以获得从 0 开始的索引。但是,我们不希望在关键路径上出现 -1...所以而是从 m 中减去 1,这样我们就不会计算总数中的最低有效字节。
找到最高集 MS1B 的问题更加复杂,因为我们没有任何位操作技巧来隔离所需的位。在这种情况下,
Extract Bits with a Single Multiplication,将它们用作表的索引。如果不允许输入值为零,则最低有效字节的值无关紧要或非零。这允许使用具有 7 位索引而不是 8 位的查找表。
根据需要进行调整。
uint64_t ReversedIndexOf_Highest_Byte_With_LSB_Set (uint64_t val) {
static const unsigned char ctz7_tab[128] = {
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
};
assert(val != 0);
assert((val & 0xFEFEFEFEFEFEFEFEULL) == 0);
val = (val * UINT64_C(0x0080402010080402)) >> 57;
return ctz7_tab[val];
}