我有np.array
np.uint8
a = np.array([randint(1,255) for _ in range(100)],dtype=np.uint8)
我希望将其拆分为低和高半字节
我可以得到低半字节
low = np.bitwise_and(a,0xF)
我可以用
获得高位high = np.bitwise_and(np.right_shift(a,4),0xF)
有某种方法可以做一些像
这样的事情>>> numpy.keep_bits(a,[(0,3),(4,7)])
numpy.array([
[low1,high1],
[low2,high2],
...
[lowN,highN]
])
我甚至不确定这会被称为什么...但我想也许一些笨拙的大师会知道一个很酷的方法来做到这一点(实际上我希望用uint32和更多变化的半字节来做这个
基本上类似于struct.unpack
但是对于矢量化的numpy操作
编辑:我使用了下面接受的答案的修改版本
这是我感兴趣的任何人的最终代码
def bitmask(start,end):
"""
>>> bitmask(0,2) == 0b111
>>> bitmask(3,5) == 0b111000
:param start: start bit
:param end: end bit (unlike range, end bit is inclusive)
:return: integer bitmask for the specified bit pattern
"""
return (2**(end+1-start)-1)<<start
def mask_and_shift(a,mask_a,shift_a):
"""
:param a: np.array
:param mask_a: array of masks to apply (must be same size as shift_a)
:param shift_a: array of shifts to apply (must be same size as mask_a)
:return: reshaped a, that has masks and shifts applied
"""
masked_a = numpy.bitwise_and(a.reshape(-1,1), mask_a)
return numpy.right_shift(masked_a,shift_a)
def bit_partition(rawValues,bit_groups):
"""
>>> a = numpy.array([1,15,16,17,125,126,127,128,129,254,255])
>>> bit_partition(a,[(0,2),(3,7)])
>>> bit_partition(a,[(0,2),(3,5),(6,7)])
:param rawValues: np.array of raw values
:param bit_groups: list of start_bit,end_bit values for where to bit twiddle
:return: np.array len(rawValues)xlen(bit_groups)
"""
masks,shifts = zip(*[(bitmask(s,e),s) for s,e in bit_groups])
return mask_and_shift(rawValues,masks,shifts)
答案 0 :(得分:3)
使用广播的单行,用于四位低位和高位半字节:
In [38]: a
Out[38]: array([ 1, 15, 16, 17, 127, 128, 255], dtype=uint8)
In [39]: (a.reshape(-1,1) & np.array([0xF, 0xF0], dtype=np.uint8)) >> np.array([0, 4], dtype=np.uint8)
Out[39]:
array([[ 1, 0],
[15, 0],
[ 0, 1],
[ 1, 1],
[15, 7],
[ 0, 8],
[15, 15]], dtype=uint8)
要概括此内容,请使用适当的位掩码和移位替换硬编码的值[0xF, 0xF0]
和[0, 4]
。例如,要将值拆分为三组,包含最高的两位,然后是剩下的两组三位,您可以这样做:
In [41]: masks = np.array([0b11000000, 0b00111000, 0b00000111], dtype=np.uint8)
In [42]: shifts = np.array([6, 3, 0], dtype=np.uint8)
In [43]: a
Out[43]: array([ 1, 15, 16, 17, 127, 128, 255], dtype=uint8)
In [44]: (a.reshape(-1,1) & np.array(masks, dtype=np.uint8)) >> np.array(shifts, dtype=np.uint8)
Out[44]:
array([[0, 0, 1],
[0, 1, 7],
[0, 2, 0],
[0, 2, 1],
[1, 7, 7],
[2, 0, 0],
[3, 7, 7]], dtype=uint8)
答案 1 :(得分:2)
所以,我不会评论你想要实现的特定逻辑运算符,因为bit-hacking不是我的专长,但是我可以告诉你应该在numpy
中查看哪些内容来实现这种定制运营商。
如果您查看numpy
来源,您会注意到numpy
中的几乎所有位操作技术都只是_MaskedBinaryOperation
的实例,例如,bitwise_and
的定义{1}}只是:
bitwise_and = _MaskedBinaryOperation(umath.bitwise_and)
这里的神奇之处在于umath
模块的形式,它通常调用numpy
构建的低级库。如果你真的想要,你可以在那里添加你的运营商,但我认为不值得在那个层面上徘徊。
尽管如此,这并不是将这些功能纳入numpy
的唯一方法。实际上,umath
模块有一个非常方便的函数frompyfunc
,可以让你将任意python函数转换为这些方便的umath
运算符之一。可以找到文档here。创建这样一个函数的一个例子如下:
>>> oct_array = np.frompyfunc(oct, 1, 1)
>>> oct_array(np.array((10, 30, 100)))
array([012, 036, 0144], dtype=object)
>>> np.array((oct(10), oct(30), oct(100))) # for comparison
array(['012', '036', '0144'],
dtype='|S4')
如果您决定要实现的按位运算符的细节,使用此接口将是实现它的最佳方法。
这不能回答100%的问题,但我认为你的问题更多的是以正确的numpy
形式实现一些自定义的按位运算符,而不是深入研究按位运算符本身。如果这不准确,请告诉我,我可以使用您在上面提到的按位运算符组合示例。