Ich habe ein Byte-Objekt oder Bytearray-Objekt, das einen gepackten Strom von 11-Bit-Ganzzahlen darstellt. (Edit: Stream ist 11-Bit Big-Endian Ganzzahlen ohne Auffüllen.)Ein Bytearray mit 11-Bit-Ganzzahlen in ein Array von 16-Bit-Ganzzahlen umwandeln
Gibt es eine einigermaßen effiziente Möglichkeit, dies zu einem Strom von 16-Bit-Ganzzahlen zu kopieren? Oder irgendein anderer ganzzahliger Typ?
Ich weiß, dass Ctypes Bitfelder unterstützt, aber ich bin mir nicht sicher, ob mir das hier überhaupt hilft.
Kann ich vielleicht einen Teil der Standard-Bibliothek "missbrauchen", die schon für andere Zwecke so etwas falsch macht?
Wenn ich auf Cython zurückgreifen muss, gibt es eine gute Implementierung, die mit variablen Bitlängen umgehen kann? I.e. nicht nur für 11 bit eingang sondern auch 12, 13, etc?
Edit: reine Python-Lösung basierend auf PM2 Ring Antwort
def unpackIntegers(data, num_points, bit_len):
"""Unpacks an array of integers of arbitrary bit-length into a
system-word aligned array of integers"""
# TODO: deal with native integer types separately for speedups
mask = (1 << bit_len) - 1
unpacked_bit_len = 2 ** ceil(log(bit_len, 2))
unpacked_byte_len = ceil(unpacked_bit_len/8)
unpacked_array = bytearray(num_points * unpacked_byte_len)
unpacked = memoryview(unpacked_array).cast(
FORMAT_CODES[unpacked_byte_len])
num_blocks = num_points // 8
# Note: zipping generators is faster than calculating offsets
# from a block count
for idx1_start, idx1_stop, idx2_start, idx2_stop in zip(
range(0, num_blocks*bit_len, bit_len),
range(bit_len, (num_blocks+1)*bit_len, bit_len),
range(7, num_points, 8),
range(-1, num_points-8, 8),
):
n = int.from_bytes(data[idx1_start:idx1_stop], 'big')
for i in range(idx2_start, idx2_stop, -1):
unpacked[i] = n & mask
n >>= bit_len
# process left-over part (missing from PM2 Ring's answer)
else:
points_left = num_points % 8
bits_left = points_left * bit_len
bytes_left = len(data)-num_blocks*bit_len
num_unused_bits = bytes_left * 8 - bits_left
n = int.from_bytes(data[num_blocks*bit_len:], 'big')
n >>= num_unused_bits
for i in range(num_points-1, num_points-points_left-1, -1):
unpacked[i] = n & mask
n >>= bit_len
return unpacked