Python 动态位操作示例
Python dynamic bit manipulation example
我目前正在编写一个 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
使用 左移 操作。我怎样才能做到这一点?谢谢!
您可以使用如下函数:
# 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
编辑:从你问题的最后一部分来看,你似乎想要 "update" val
给出一些新的整数。
这可以使用上述方法完成(更新 arr
,在更新的 arr
上再次调用 bits2int
),或 "manually",使用:
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
请注意,<<=
运算符是 in-place/augmented 左移运算符,|=
运算符是 in-place/augmented 按位或运算符。
更新
根据评论中的讨论,您不仅要跟踪值,还要跟踪位数。这比上面的简单功能更复杂。这是您可以使用的基本 class:
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。它按 "throwing out" 最左边的位执行,如您所问。
我还为这 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 个元素的 1 列表,将其转换为 BitArray
,然后比较结果值(与int(BitArrayInstance)
) 我们期望的是:
# Test 600 element array :)
arr = [1] * 600
b3 = BitArray.from_array(arr)
print(int(b3) == ((2**600) - 1)) # True
我目前正在编写一个 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
使用 左移 操作。我怎样才能做到这一点?谢谢!
您可以使用如下函数:
# 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
编辑:从你问题的最后一部分来看,你似乎想要 "update" val
给出一些新的整数。
这可以使用上述方法完成(更新 arr
,在更新的 arr
上再次调用 bits2int
),或 "manually",使用:
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
请注意,<<=
运算符是 in-place/augmented 左移运算符,|=
运算符是 in-place/augmented 按位或运算符。
更新
根据评论中的讨论,您不仅要跟踪值,还要跟踪位数。这比上面的简单功能更复杂。这是您可以使用的基本 class:
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。它按 "throwing out" 最左边的位执行,如您所问。
我还为这 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 个元素的 1 列表,将其转换为 BitArray
,然后比较结果值(与int(BitArrayInstance)
) 我们期望的是:
# Test 600 element array :)
arr = [1] * 600
b3 = BitArray.from_array(arr)
print(int(b3) == ((2**600) - 1)) # True