Is there easy way for python to convert from 8 bits to 5 bits. Currently I am using this code to do it:
def convertbits(data, frombits, tobits, pad=True):
acc = 0
bits = 0
ret = []
maxv = (1 << tobits) - 1
max_acc = (1 << (frombits + tobits - 1)) - 1
for value in data:
if value < 0 or (value >> frombits):
return None
acc = ((acc << frombits) | value) & max_acc
bits += frombits
while bits >= tobits:
bits -= tobits
ret.append((acc >> bits) & maxv)
if pad:
if bits:
ret.append((acc << (tobits - bits)) & maxv)
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
return None
return ret
is there a better way?
Edit: output should be list of 5bit integers without loosing any data in proccess
it should work like:
>>> hello = [ord(letter) for letter in 'hello']
>>> hello
[104, 101, 108, 108, 111]
>>> convertbits(hello, 8, 5)
[13, 1, 18, 22, 24, 27, 3, 15]
>>>
Well, this is relatively memory-inefficient as it converts individual bits to strings, but it seems to work:
import itertools
def convertbits(data, From, To):
bits_orig = itertools.chain.from_iterable(bin(n)[2:].zfill(From) for n in data)
chunks = iter(lambda: ''.join(itertools.islice(bits_orig, To)), '')
return [int(n, 2) for n in chunks]
print(convertbits(b'hello', 8, 5))
print([13, 1, 18, 22, 24, 27, 3, 15])
Once you got a stream of bits of the numbers (bits_orig), it's then simple to slice this stream into chunks of equal length (chunks) (this version doesn't do padding but it's fairly simple to implement) and convert the strings of ones and zeros back to numbers.
If you're working with 8-bit numbers exclusively, here's an algorithm that's 8.5(!) times faster than the one above:
from collections import deque
def convert8bits(data, To):
number = int.from_bytes(data, 'big')
ret = deque()
th = (1 << To) - 1
while number:
ret.appendleft(number & th)
number >>= To
return ret
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With