Как я представляю и работаю с N-битными векторами в Python?

в задании, над которым я сейчас работаю, нам нужно работать с битовыми векторами, но я очень не уверен, как это сделать в Python. Они должны быть от 4 бит до 20 бит. Я никогда раньше не работал с битовым вектором, но я думаю, что можно было бы создать массивы неподписанных байтов, которыми вы управляли, используя обычные операции AND/OR/XOR.

на важное ограничение здесь: я не могу положиться на любой библиотеки, отличные от поставляемых со стандартным Python.

Я думаю, что знаю, как я бы это сделал в C, используя массивы 8 бит беззнаковых байтов: например, чтобы превратить 18-й бит нулевого массива в единицу, я бы сделал что-то вроде my_bit_array[3] &= 1

но, поскольку Python-это динамически типизированный и не имеют встроенный тип массива, как бы я идти о делать это в подходящие для Python способ?

и возможно ли это (как?) выразить битовый вектор размером 20? Я думаю возможно сделать 24 бит / 3 байтовый вектор и игнорирование 4 бит.

7 ответов


библиотека BitVector является библиотекой pure-Python для этой цели и должен соответствовать указанным вами потребностям.


Я удивлен, что никто не упомянул ints (или я думаю long в Python 2). ints может быть сколь угодно большим, вы можете использовать побитовые операторы на них, они быстры, и код выглядит как битный код в C (я считаю, что это преимущество).

x = 0 # empty
x |= 1<<19 # set bit 19
x &= ~(1<<19) # clear bit 19
x ^= 1<<19 # toggle bit 19
x = ~x # invert *all* bits, all the way to infinity
mask = ((1<<20)-1) # define a 20 bit wide mask
x &= mask # ensure bits 20 and higher are 0
x ^= mask # invert only bits 0 through 19

(x >> 19) & 1 # test bit 19
(x >> 16) & 0xf # get bits 16 through 20.

я использовал это для bitvectors сотни бит длиной.


на bitarray модуль делает это эффективно с логическими значениями.


Он имеет списки, которые вы можете заполнить bools:

[False] * 20

использовать struct модуль.


существует также pure-Python python-bitstring (С поддержкой Python 3).


немного устарел, но я собираюсь оставить еще один вариант stdlib здесь просто для сравнения. Это также легко сделать с помощью ctypes модуль.

например:

и возможно ли это (как?) выразить битовый вектор размером 20 ? Я думаю, возможно, сделать 24 бит / 3 байтовый вектор и игнорировать 4 биты.

class Simple(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
                 ('one', ctypes.c_ubyte, 8),
                 ('two', ctypes.c_ubyte, 8),
                 ('three', ctypes.c_ubyte, 8)
               ]

s = Simple(0, 2, 256)
bytearray(s)        # bytearray(b'\x00\x02\x00')
s = Simple(0, 2, 255)
bytearray(s)        # bytearray(b'\x00\x02\xff')

class Simple(ctypes.BigEndianStructure):
    _pack_ = 1
    _fields_ = [
                 ('one', ctypes.c_ubyte, 8),
                 ('two', ctypes.c_ubyte, 8),
                 ('three', ctypes.c_ubyte, 8)
               ]

s = Simple(0, 2, 256)
bytearray(s)        # bytearray(b'\x00\x02\x00')
s = Simple(0, 2, 255)
bytearray(s)        # bytearray(b'\x00\x02\xff')

s.two |= 3
bytearray(s)        # bytearray(b'\x00\x03\xff')

или что-то прямо вперед, как это:

class bit_vector(Structure):
    _fields_ = [('bits', c_uint32, 24),
                ('unused', c_uint32, 8),
                ]

bv = bit_vector()
# turn on the 18th bit -- being explicit just to demo it
bv.bits |= int('000000000000000001000000', 2)
bin(bv.bits)   # 0b1000000