1

I'm currently using this little function for converting a byte to a list of integer bits, because I need to iterate over the single bits of a byte.

def byteToBitList(byte):
    return [int(bit) for bit in "{0:08b}".format(byte)]

but I don't think it's very elegant. Is there a better way to do this? Possibly without using strings?

blubbi
  • 57
  • 6

4 Answers4

2

You can always benefit from using bitwise operations, which works with a standard integer object. Simply shift your number one bit at time and collect the right-most bit value. For instance:

>>> byte = 0xFC
>>> list_size = 8
>>> [(byte >> i) & 1 for i in range(list_size)][::-1] # reverse this array, since left-most bits are evaluated first.
[1, 1, 1, 1, 1, 1, 0, 0]

Timing using IPython: 1000000 loops, best of 3: 1.54 µs per loop

It's even possible to generate this list without reversing the array:

>>> byte = 0xFC
>>> list_size = 8
>>> [(byte & (1 << (list_size - 1 - k))) >> (list_size - 1 - k) for k in range(list_size)]
[1, 1, 1, 1, 1, 1, 0, 0]

Timing using IPython: 100000 loops, best of 3: 2.3 µs per loop. Apparently, it's faster to reverse a list than to use two shifts!

Also, this Stack Overflow thread contains a pretty similar question.

Community
  • 1
  • 1
Matheus Portela
  • 2,420
  • 1
  • 21
  • 32
2

If you want to avoid string operations, you can use binary operations, namely shifts << and >> combined with the logical and &.

>>> def byteToBitList(byte):
    return [(byte & (1 << k)) >> k for k in range(8)]

>>> byteToBitList(0xfc)
[0, 0, 1, 1, 1, 1, 1, 1]
Michaël Le Barbier
  • 6,103
  • 5
  • 28
  • 57
  • 1
    Notice that your output is reversed: `0xFC` is `0b11111100`. I've written an answer to this question showing how to get the bit list in the proper order. – Matheus Portela Feb 02 '16 at 10:30
1

You could use following solution which is a bit faster :

byte = 0xfc

In [206]: list(map(int, bin(byte)[2:].zfill(8)))
Out[206]: [1, 1, 1, 1, 1, 1, 0, 0]

Timing:

In [209]: %timeit byteToBitList(byte)
100000 loops, best of 3: 5.69 us per loop

In [211]: %timeit list(map(int, bin(byte)[2:].zfill(8)))
100000 loops, best of 3: 4.27 us per loop
Anton Protopopov
  • 30,354
  • 12
  • 88
  • 93
1

You can combine bin() and a little pruning with str.zfill() to convert the integer to it's binary representation:

def byteToBitList(byte):
    return [int(bit) for bit in bin(byte)[2:].zfill(8)]

This assumes that byte is indeed an unsigned integer of value 0-255. Any larger and the resultant list will exceed 8 bits although the result will be correct, just not zero padded.

mhawke
  • 84,695
  • 9
  • 117
  • 138