有效地生成二进制掩码中的所有整数

时间:2015-03-13 00:12:36

标签: combinatorics

假设我有一些二进制掩码mask。 (例如0b101011011101)

是否有一种有效的方法来计算所有整数k,以便k & mask == k? (其中&是按位AND运算符)(或者,k& ~mask == 0)

如果maskm个,那么正好有2个 m 数字满足这个属性,所以看起来应该有某种过程就是O (2 )。枚举小于掩码的整数是浪费的(虽然很容易消除不适用的值)。

2 个答案:

答案 0 :(得分:0)

我想通了......你可以识别所有单个位模式,如下所示,因为在计算k时,任何整数k & (k-1)的最低有效位被清除:

def onebits(x):
    while x > 0:
        # find least significant 1 bit
        xprev = x
        x &= x-1
        yield x ^ xprev

然后我可以使用ruler function以1位的各种组合进行异或,以模拟每次切换计数器的哪些位:

def maskcount(mask):
    maskbits = []
    m = 0
    for ls1 in onebits(mask):
        m ^= ls1
        maskbits.append(m)
    # ruler function modified from 
    # http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators
    def ruler(k):
        for i in range(k):
            yield i
            for x in ruler(i): yield x    
    x = 0
    yield x
    for k in ruler(len(maskbits)):
        x ^= maskbits[k]
        yield x

看起来像这样:

>>> for x in maskcount(0xc05):
...     print format(x, '#016b')
0b00000000000000
0b00000000000001
0b00000000000100
0b00000000000101
0b00010000000000
0b00010000000001
0b00010000000100
0b00010000000101
0b00100000000000
0b00100000000001
0b00100000000100
0b00100000000101
0b00110000000000
0b00110000000001
0b00110000000100
0b00110000000101

答案 1 :(得分:0)

解决问题的一种简单方法是找到在掩码中设置的位,然后简单地用i计数,然后用掩码中的相应位替换i的位。

def codes(mask):
    bits = filter(None, (mask & (1 << i) for i in xrange(mask.bit_length())))
    for i in xrange(1 << len(bits)):
        yield sum(b for j, b in enumerate(bits) if (i >> j) & 1)

print list(codes(39))

它为每次迭代提供O(log(N))工作(其中N是mask中设置的位数)。

可以提高效率,并通过使用gray codes进行计数,每次迭代执行O(1)工作。使用格雷码计数,每次迭代只改变一个位,因此可以有效地更新当前值v。显然,这比上面的简单解决方案更难理解。

def codes(mask):
    bits = filter(None, (mask & (1 << i) for i in xrange(mask.bit_length())))
    blt = dict((1 << i, b) for i, b in enumerate(bits))
    p, v = 0, 0
    for i in xrange(1 << len(bits)):
        n = i ^ (i >> 1)
        v ^= blt.get(p^n, 0)
        p = n
        yield v

print list(codes(39))

使用格雷码的一个缺点是结果不是按数字顺序返回的。但幸运的是,这不是问题的一个条件!