Упаковка 4 Целые числа как ONE BYTE?

У меня есть четыре целых числа { a, b, c, d }, которые могут иметь следующий диапазон значений:

a - {0 или 1} (1 бит)

b - {0 или 1} (1 бит)

c - {0, 1, 2,..., 7} (3 бита)

d - {0, 1, 2,..., 7} (3 бита)

Сначала я хотел бы упаковать их в один байт, который затем можно записать в двоичный файл. позже я хотел бы распаковать этот один байт и получить от него кортеж в форме (a, b, c, d).

Я знаю, как читать/записывать байт в двоичный файл в Python. Но как мне сделать упаковку/распаковку битов?

Ответы

Ответ 1

Используйте shift и побитовое ИЛИ, затем преобразуйтесь в символ, чтобы получить "байт":

x = chr(a | (b << 1) | (c << 2) | (d << 5))

Чтобы снова распаковать этот байт, сначала преобразуйте его в целое число, затем сдвиньте и используйте побитовое значение AND:

i = ord(x)
a = i & 1
b = (i >> 1) & 1
c = (i >> 2) & 7
d = (i >> 5) & 7

Объяснение: Первоначально у вас есть

0000000a
0000000b
00000ccc
00000ddd

Левые смены дают вам

0000000a
000000b0
000ccc00
ddd00000

Побитовое ИЛИ приводит к

dddcccba

Преобразование в символ преобразует его в один байт.

Распаковка: четыре разных сдвига вправо приводят к

dddcccba
0dddcccb
00dddccc
00000ddd

Маскирование (побитовое И) с помощью 1 (0b00000001) или 7 (0b00000111) приводит к

0000000a
0000000b
00000ccc
00000ddd

снова.

Ответ 2

def encode(a, b, c, d):
  return a | b << 1 | c << 2 | d << 5

def decode(x):
  return x & 1, (x >> 1) & 1, (x >> 2) & 7, (x >> 5) & 7

Ответ 3

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

Чтобы упаковать и преобразовать в байт:

x = bitstring.pack('2*uint:1, 2*uint:3', a, b, c, d).bytes

и распаковать:

a, b, c, d = bitstring.BitArray(bytes=x).unpack('2*uint:1, 2*uint:3')

Это, вероятно, слишком велико для вашего примера, но полезно, когда ситуация усложняется.

Ответ 4

Довольно просто. Маска (для диапазона), сдвиньте их на место и/или вместе.

packed = ((a & 1) << 7) | ((b & 1) << 6) | ((c & 7) << 3) | (d & 7)

a = (packed >> 7) & 1
b = (packed >> 6) & 1
c = (packed >> 3) & 7
d = packed & 7