【问题标题】:fast way to shift bits to positions given in a mask将位移动到掩码中给定位置的快速方法
【发布时间】:2018-11-15 18:44:04
【问题描述】:

我正在寻找一种快速迭代掩码中所有可能的位分配的方法。

例子:

掩码 = 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 中执行操作的更快方法,或者是否有更快的方法来创建此分配。 也许是一些位魔术或没有“写后读”和“读后写”冲突的方式?

【问题讨论】:

  • 我无法理解shiftBits 应该做什么?从给定的示例看起来,结果包含0 和所有非零数字,其&amp; 的掩码不等于零。 count 代表什么?
  • 它将最低有效位从数字移动到掩码中最低有效 1 的位置。掩码中为 0 的位置在结果中保持为 0。
  • 我认为你不能比O(k 2^k) 更快,其中 k 是找到结果集的设置位数。
  • 是否允许使用 pdep 内在函数?仅适用于现代 x86,在 Ryzen 上运行缓慢

标签: c++ bit-manipulation


【解决方案1】:

更新版本,将升序枚举替换为更简单的表达式:

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);

【讨论】:

  • 谢谢,没想到这么简单
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多