【问题标题】:Incrementing 'masked' bitsets递增“屏蔽”位集
【发布时间】:2017-11-29 17:28:36
【问题描述】:

我目前正在编写一个树枚举器,但遇到了以下问题:

我正在查看掩码位集,即设置位是掩码子集的位集,即0000101 和掩码1010101。我想要完成的是增加位集,但仅限于屏蔽位。在此示例中,结果将是 0010000。为了更清楚一点,只提取屏蔽位,即0011,将它们递增到0100,然后再次将它们分配给屏蔽位,得到0010000

除了使用位扫描和前缀掩码的组合手动执行操作之外,是否有人看到了一种有效的方法?

【问题讨论】:

    标签: c++ c bit-manipulation intrinsics


    【解决方案1】:

    如果迭代的顺序不是那么重要,并且减量操作可以满足您的需求,则可以只使用两个操作:

    开始吧

    x = mask

    并使用

    获取先前的值

    x = (x - 1) & mask

    x - 1 部分将最后一个非零位更改为零,并将所有较低有效位设置为 1。然后& mask 部分只留下掩码位。

    【讨论】:

    • 2 个操作,很好。但是我认为这是相同的方法,只是通过零传播借位,而不是通过零进行。
    • @zch,没错,谢谢。我会改写答案
    • 仅当 x 以所有非掩码位清除开始时才有效。
    • @Jasen,当然。但是设置那些非掩码位并不难。其他答案也有类似的问题。
    【解决方案2】:

    虽然与公认的答案相比不直观,但这只需 3 个步骤:

    x = -(x ^ mask) & mask;
    

    这可以按照zch的建议进行验证:

      -(x ^ mask)
    = ~(x ^ mask) + 1  // assuming 2's complement
    = (x ^ ~mask) + 1
    = (x | ~mask) + 1  // since x and ~mask have disjoint set bits
    

    然后它就等同于接受的答案。

    【讨论】:

    • zch 的回答很直观,我一看就知道是对的,因为他解释的很清楚。这个答案的逻辑是什么?这个公式如何产生预期的效果?我很好奇发现的过程,这里洞察的本质。
    • -(x^mask) == ~((x ^ mask) - 1) == ~(x ^ mask) + 1 == (x ^ ~mask) + 1 == (x | ~mask) + 1。最后一个等式成立,因为位集是不相交的,其他的总是正确的(至少在 2-complement 中)。
    • 那些对我得出这个答案所采取的步骤感到好奇的人可以参考this page
    • 也许值得指出的是,这些优化并不相同,这通常与人们进行比特旋转有关:godbolt.org/g/7VWXas - 尽管实际上哪个更短似乎取决于编译器。不知道哪个会更快或者差异是否显着。
    【解决方案3】:

    只需用 1 填充非掩码位,以便它们传播进位:

    // increments x on bits belonging to mask
    x = ((x | ~mask) + 1) & mask;
    

    【讨论】:

    • 这是一个不错的技巧......几乎我说的魔法没有:)
    • @EugeneSh。永远不要相信事实并非如此。
    • 可能对 OP 来说并不重要,因为他们接受了,但可能应该注意的是,这会将非掩码位归零。如果它们在其他地方需要,您必须更加小心地替换x。可能是x = (x & ~mask) | (((x | ~mask) + 1) & mask);
    • @TripeHound 如果不需要它们,那么即使使用位掩码又有什么意义?
    • @someonewithpc 不确定您要说/问什么。我不知道 why OP 需要增加一组不相邻的位,所以我不知道原始值中的 other 位是否重要.例如。如果原始值为0101101(例如,非掩码位中的.1.1.0. 和“计数器”中的0.0.1.1)他们是否需要 0111000(@ 的新“计数器” 987654328@ 同时保留.1.1.0.) 或者只是0010000 可以接受。这个答案(可能还有其他答案,虽然我没有检查过)给了后者;如果需要,我的版本应该提供前者。
    猜你喜欢
    • 2017-07-02
    • 1970-01-01
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多