Reputation: 365
I currently use the following code to convert an array of bytes which represent little endian signed 24 bit integers into a list of signed 32 bit integers.
xs = list(bytes_object)
ys = [xs[x:x+3] + [255] if xs[x+2] & 128 else xs[x:x+3] + [0]
for x in range(0, len(xs), 3)]
int32s = [struct.unpack('<i', bytes(y))[0] for y in ys]
Is there a more pythonic or efficient way to handle the conversion?
Upvotes: 4
Views: 2736
Reputation: 31
Here are my solutions. -8388608
-> FF80 0000
(32bit) or FFFF FFFF FF80 0000
(64bit) does the magic to convert the signed values.
test_bytes = b'\x58\x18\x85'
def byte3toint(tmp, signed=True):
b = tmp[0] | tmp[1] << 8 | tmp[2] << 16 # restore the bit represention
if signed and tmp[2] & 128:
b |= -8388608
return b
assert byte3toint(test_bytes) == int.from_bytes(test_bytes, 'little', signed=True)
Upvotes: 0
Reputation: 2834
outside of numpy, this is pretty pythonic:
bytes_object = b'\x01\x00\x00\x00\x00\xf0'
[int.from_bytes(bytes_object[x:x+3], byteorder='little', signed=True) for x in range(0, len(bytes_object), 3)]
Upvotes: 2
Reputation: 366053
Of the top of my head, something like this:
import numpy as np
# First convert the buffer to an array of 3-vectors of uint8s
a3 = np.frombuffer(x, dtype=np.uint8).reshape(-1, 3)
# Now sign-extend it to an array of 4-vectors of uint8s
signs = (a3[..., 0] > 0x80) * 0xFF
a4 = np.concatenate((signs.reshape(-1, 1), a), axis=1)
# Now convert that to an array of int32s
i = a4.view(np.int32)
# And what you eventually wanted to do was convert to float64?
f = i.astype(np.float64)
I'm sure I've made at least one mistake (surely this won't work on a big-endian system, at least), and I don't have a computer with numpy installed in front of me, but hopefully that gets you started. No need to do anything in a Python loop.
Upvotes: 3