我正在寻找一种快速方法来遍历掩码中设置的所有可能的位分配。
示例:
mask = 0b10011
结果= {0b00000, 0b00001, 0b00010, 0b00011, 0b10000, 0b10001, 0b10010, 0b10011}
我需要遍历所有这些。
目前,我使用与此类似的代码,效果很好:
int count = popCount(mask);
uint64_t number = 0;
for(uint64_t number = 0; number < (1 << count); ++number)
{
uint64_t result = shiftBits(mask, number, count);
//work with result
//only some light operations
}
// shiftBits(0b10011, 0b101, 3) == 0b10001
// shiftBits(0b10011, 0b111, 3) == 0b10011
// shiftBits(0b10011, 0b000, 3) == 0b00000
uint64_t shiftBits(uint64_t mask, uint64_t number, int count) {
uint64_t result = 0;
for(int i = 0; i < count; ++i)
{
uint64_t least = (mask & ~(mask - 1)); // get uint64_t with only least significant 1 set
uint64_t bitSet = number & uint64_t(1); // check if last bit in number is set
result |= least * bitSet; // if last bit is set, then set corresponding position in result
mask &= mask - 1; // clear lsb set in mask
number = number >> 1; // make 2nd lsb the next one to check
}
return result;
}
shiftBits示例:
mask = 0b10011001
number = 0b1 01 0 = 0b1010
result = 0b10001000
但是我想知道是否有人知道更快的方法来执行shiftBits中完成的操作,或者是否有更快的方法来创建此分配。 也许有些魔术或某种方式没有“写后读”和“读后写”冲突?
答案 0 :(得分:9)
更新版本,用一个更简单的表达式替换升序枚举:
uint64_t i = 0;
do {
// use i
i = (i - mask) & mask;
} while (i);
这确实与旧答案具有相同的作用,但是节省了操作。您可以将其视为减去-1而不是加1,但这是被屏蔽的-1。
无需移动:您可以进行带掩码的增量。此处的想法是通过将掩码的零点暂时设置为1,然后再将其清除,从而使进位通过零点。例如:
uint64_t i = 0;
do {
// use i
i = ((i | ~mask) + 1) & mask;
} while (i);
向后迭代稍微简单一点,因为减量是通过零借位的,而被掩盖的位已经是零,例如:
uint64_t i = 0;
do {
i = (i - 1) & mask;
// use i
} while (i);