Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integer to bitfield as a list

I've created a method to convert an int to a bitfield (in a list) and it works, but I'm sure there is more elegant solution- I've just been staring at it for to long.

I'm curious, how would you convert a int to a bitfield represented in a list?

def get(self):
    results = []

    results.append(1 if (self.bits &   1) else 0)
    results.append(1 if (self.bits &   2) else 0)
    results.append(1 if (self.bits &   4) else 0)
    results.append(1 if (self.bits &   8) else 0)
    results.append(1 if (self.bits &  16) else 0)
    results.append(1 if (self.bits &  32) else 0)
    results.append(1 if (self.bits &  64) else 0)
    results.append(1 if (self.bits & 128) else 0)

    return results

def set(self, pin, direction):
    pin -= 1
    if pin not in range(0, 8): raise ValueError

    if direction: self.bits |= (2 ** pin)
    else: self.bits &=~(2 ** pin)
like image 339
tMC Avatar asked Apr 25 '12 18:04

tMC


2 Answers

How about this:

def bitfield(n):
    return [int(digit) for digit in bin(n)[2:]] # [2:] to chop off the "0b" part 

This gives you

>>> bitfield(123)
[1, 1, 1, 1, 0, 1, 1]
>>> bitfield(255)
[1, 1, 1, 1, 1, 1, 1, 1]
>>> bitfield(1234567)
[1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1]

This only works for positive integers, though.

EDIT:

Conversion to int using int() is a bit overkill here. This is a lot faster:

def bitfield(n):
    return [1 if digit=='1' else 0 for digit in bin(n)[2:]]

See the timings:

>>> import timeit
>>> timeit.timeit("[int(digit) for digit in bin(123)[2:]]")
7.895014818543946
>>> timeit.timeit("[123 >> i & 1 for i in range(7,-1,-1)]")
2.966295244250407
>>> timeit.timeit("[1 if digit=='1' else 0 for digit in bin(123)[2:]]")
1.7918431924733795
like image 59
Tim Pietzcker Avatar answered Oct 19 '22 10:10

Tim Pietzcker


This doesn't use bin:

 b = [n >> i & 1 for i in range(7,-1,-1)]

and this is how to handle any integer this way:

 b = [n >> i & 1 for i in range(n.bit_length() - 1,-1,-1)]

See bit_length.

If you want index 0 of the list to correspond to the lsb of the int, change the range order, i.e.

b = [n >> i & 1 for i in range(0, n.bit_length()-1)]

Note also that using n.bit_length() can be a point of failure if you're trying to represent fixed length binary values. It returns the minimum number of bits to represent n.

like image 36
georg Avatar answered Oct 19 '22 11:10

georg