Python动态位操作示例

时间:2015-03-20 05:01:03

标签: python bit-manipulation

我目前正在编写一个需要位操作的python程序。

输入是整数数组的序列,比如说

1, 2, 3, 4, 5, 6, 7, 8

输出是检查每个整数是等于还是大于3.如果是,则为1,否则为0.输出为二进制整数

00111111

我该怎么做?

如果有新号码,请说出9.我需要删除序列中的第一个数字,比如序列中的1。所以我的新序列将是:

2,3,4,5,6,7,8,9

然后结果应为01111111。但是我想从我的旧整数00111111使用左移操作。我怎样才能做到这一点?谢谢!

1 个答案:

答案 0 :(得分:3)

您可以使用以下功能:

# Assumes msb first, lsb last, bits is iterable of integers in [0,1]
def bits2int(bits):
    v = 0
    for b in bits:
        v <<= 1
        v += b
    return v

然后,根据您的输入数组arr,使用以下命令调用它:

arr = [1, 2, 3, 4, 5, 6, 7, 8]
val = bits2int([i >= 3 for i in arr])

print(val)                   # 63
print("{:08b}".format(val))  # 00111111

对于您的其他输入数组,您可以使用以下命令调用它:

arr = [2,3,4,5,6,7,8,9]
val = bits2int([i >= 3 for i in arr])

print(val)                  # 127
print("{:08b}".format(val)  # 01111111

修改:从问题的最后部分开始,看起来您希望在给定一些新整数的情况下“更新”val

可以使用上述方法(更新arr,再次在更新的bits2int上调用arr)或“手动”,使用以下方法完成:

arr = [1, 2, 3, 4, 5, 6, 7, 8]
val = bits2int([i >= 3 for i in arr])
# Now, val = 63 = 0b00111111

# Handle additional integer
new_int = 9             # Give the additional integer a name, to make it clear
val <<= 1               # Shift up all bits
val |= (new_int >= 3)   # Set lowest bit according to some logic
                        #   (here, if new_int >= 3)
print(val)
print("{:08b}".format(val))

最后,val与上面第二个bits2int调用的输出相同:

127
01111111

请注意,<<=运算符是就地/扩充的左移运算符,|=运算符是就地/扩充的按位运算符。


<强>更新

根据评论中的讨论,您不仅要跟踪值,还要跟踪位数。这比上面的简单功能更复杂。这是您可以使用的基础课程:

class BitArray(object):
    @classmethod
    def from_array(cls, bits=None):
        self = cls()
        if bits is None: bits = []
        self.val = 0
        for b in bits:
            self.val <<= 1
            self.val += b
        self.nbits = len(bits)
        return self

    @classmethod
    def from_int(cls, val, nbits=None):
        self = cls()
        if nbits is None: nbits = val.bit_length()
        self.val = val
        self.nbits = nbits
        return self

    # Define equality
    def __eq__(self,  other):
        if self.val   != other.val:   return False
        if self.nbits != other.nbits: return False
        return True

    # Better representation of BitArray object
    def __repr__(self):
        return "BitArray(nbits=%d, val=%d)" % (self.nbits, self.val)

    # Output a binary string of nbits width, or width if specified (width must be >= nbits)
    def binstr(self, width=None):
        if width is None: width = self.nbits
        assert width >= self.nbits
        return "{:b}".format(self.val).zfill(width)

    # Conversion to int e.g. int(BitArrayInstance)
    def __int__(self):
        return self.val

    # "in-line" left shift
    def __ilshift__(self, n):
        self.val <<= n
        self.nbits += 1
        return self

    # "in-line" bitwise or
    def __ior__(self, v):
        self.val |= v
        return self

    # Helper function to generate a bit mask
    def _mask(self):
        return (1 << self.nbits) - 1

    # Trim n bits off the left side (truncate n most significant bits)
    def ltrim(self, n):
        self.nbits = max(0, (self.nbits - n))
        self.val &= self._mask()

    # "Pops" off msb, shifts all bits up 1, sets lsb to v
    def rotate_in(self, v):
        v = int(v)
        assert v in [0,1]
        self.ltrim(1)
        self.__ilshift__(1)
        self.__ior__(v)
        return self

现在,在执行相同的<<=|=操作后,您可以使用ltrim方法删除最左侧的位/ msb:

arr = [1, 2, 3, 4, 5, 6, 7, 8]
b1 = BitArray.from_array([i >= 3 for i in arr])
print(b1)
new_int = 9
b1 <<= 1
b1 |= (new_int >= 3)
b1.ltrim(1)
print(b1)

输出:

BitArray(nbits=8, val=63)
BitArray(nbits=8, val=127)

请注意,两个打印功能中的nbits值相同。 <<= 1会将nbits增加1,然后ltrim(1)会将其减少1,然后返回8.它会像你问的那样“抛弃”最左边的一点。

我还为这3个操作rotate_in(bit_val)提供了便利功能。您可以通过以下方式使用它:

arr = [1, 2, 3, 4, 5, 6, 7, 8]
b2 = BitArray.from_array([i >= 3 for i in arr])
print(b2)
new_int = 9
b2.rotate_in(new_int >= 3)
print(b2)

此输出(与上述相同):

BitArray(nbits=8, val=63)
BitArray(nbits=8, val=127)

我们可以验证这两个BitArray

等效
# Ensure b1 equals b2
print(b1 == b2)  # True

最后,为了验证这对于长度为600的输入数组也是如此,我们创建一个600个元素的1s列表,将其转换为BitArray,然后比较结果值(int(BitArrayInstance) 1}})我们期望它:

# Test 600 element array :)
arr = [1] * 600
b3 = BitArray.from_array(arr)
print(int(b3) == ((2**600) - 1))  # True