python: преобразовать строку бит ('0', '1') в массив знаковых 32битных чисел
Есть срока бит: '01010101...'
Подскажите как поэлегантнее преобразовать ее в массив 32битных знаковых чисел?
Решение в лоб работает, но оно некрасивое :)
nums = []
for i in range(0, len(bits), 32):
value = int(bits[i:i + 32], 2)
nums.append(value if value <= 0x7fffffff else (value - 4294967296))
return nums
Что-нибудь из арсенала numpy или struct + bitarray
Ответы (3 шт):
Если на "голом" Python, то я бы сделал в два отдельных этапа: преобразование битов в байты, потом преобразование байт в знаковые инты. Получится длиннее, но без вычитаний магических чисел:
def bits_to_bytes(bits: str):
for i in range(0, len(bits), 8):
yield int(bits[i : i + 8], 2)
def bytes_to_ints(b: bytes):
for i in range(0, len(b), 4):
yield int.from_bytes(b[i : i + 4], "big", signed=True)
import random
n = 10 # В итоге должно получиться 10 чисел
bits = "".join(random.choices("01", k=8 * 4 * n))
print(bits)
bts = bytes(bits_to_bytes(bits))
print(bts)
ints = list(bytes_to_ints(bts))
print(ints)
Пример вывода:
10010011000101110011111000111100100110111110011001001001110111100110110001101000011010011011101011001011011110110010101010000110110001010000000010100100011010111101110101100111100110100011111001111010101110110011111100011100000110000011001110111000010010011111010011101010110101110110100011000000001101111000010110100101
b'\x93\x17><\x9b\xe6I\xdelhi\xba\xcb{*\x86\xc5\x00\xa4k\xddg\x9a>z\xbb?\x1c\x183\xb8I\xf4\xea\xd7h\xc07\x85\xa5'
[-1827193284, -1679406626, 1818782138, -881120634, -989813653, -580412866, 2059091740, 406042697, -185936024, -1070103131]
как вариант
def f(x):
return np.packbits(np.fromiter(x, dtype='b'), bitorder='big').view(dtype='>i4')
>>> x = f'{-987654321 & 0xffffffff:032b}{1234567890:032b}'
>>> x
'1100010100100001100101110100111101001001100101100000001011010010'
>>> f(x)
array([-987654321, 1234567890], dtype=int32)
Голый питон без циклов. Строка переводится в целое число, целое число в массив байт, массив байт в массив четырёхбайтовых целых, массив четырёхбайтовыx целых в массив целых. По пути порядок значений перевернулся:
import array
def bits_to_ints(bits):
assert len(bits) % 32 == 0
i = int(bits, 2)
b = i.to_bytes(len(bits) // 8, 'little', signed=False)
a = array.array('i')
a.frombytes(b)
return list(a[::-1])
bits = (
'10000000000000000000000000000000' # -2147483648
'11111111111111111111111111110110' # -10
'11111111111111111111111111111111' # -1
'00000000000000000000000000000000' # 0
'00000000000000000000000000000010' # 2
'00000000000000000000000000010100' # 20
'01111111111111111111111111111111' # 2147483647
)
print(bits_to_ints(bits))
$ python restore_ints.py [-2147483648, -10, -1, 0, 2, 20, 2147483647]
Алгоритм линейный:
число время
бит работы (c)
10^5 0.0003
10^6 0.0030
10^7 0.0291
10^8 0.2974
10^9 2.9931
P.S. Это извращение. Если вы понимаете почему в конце нужно перевернуть массив - вы молодец.
P.P.S Последнее преобразование в list можно не делать. Целые в array такие же целые как и любые другие.