2012-04-25 2 views
8

Я создал метод преобразования int в битовое поле (в списке), и он работает, но я уверен, что есть более элегантное решение - я просто смотрел на него долго.Целое число с битовым полем как список

Мне интересно, как бы вы конвертировали int в битовое поле, представленное в 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) 

ответ

22

Как об этом:

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

Это дает

>>> 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] 

это работает только для положительных целых чисел, хотя.

EDIT:

Преобразование в int с использованием int() немного избыточна здесь. Это намного быстрее:

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

Смотрите тайминги:

>>> 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 
+1

+1 для хороших соображений синхронизации – snugglo

+0

'[123 >> i & 1 для i в диапазоне (7, -1, -1)] 'является самым быстрым на моей машине. – tMC

+0

@tMC: Я переработал тайминги на обоих моих компьютерах (Win 7 Ultimate 64bit) под Python 2.7.3 и 3.2.3, и мое решение всегда было быстрее, по крайней мере, на 20% (Python 2) и 45% (Python 3). –

4

Попробуйте

>>>n=1794 
>>>bitfield=list(bin(n))[2:] 
>>>bitfield 
['1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '0'] 

Это не работает при отрицательных п, хотя и, как вы видите, дает вам список строк

+1

+1, я, кажется, забыл, что существует конструктор 'list()' все время. – Fenikso

+0

Даже если он не возвращает список целых чисел. – Fenikso

+0

Это не то, о чем просил tMC. Ему нужен список целых чисел, вы даете ему список строк. Так же хорошо, как конструктор 'list()', это не правильный инструмент здесь. –

16

Это не используется bin:

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

и это, как справиться с любым целым числом, таким образом:

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

См bit_length.

Если вы хотите индекс 0 из списка, чтобы соответствовать LSB в междунар, изменить порядок диапазона, т.е.

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

Заметим также, что использование n.bit_length() может быть точкой сбоя, если вы пытаетесь представить двоичные значения фиксированной длины. Он возвращает минимальное количество бит для представления n.

+0

Это прекрасно - я знал, что было понимание списка, которого я отсутствовал – tMC

+3

Конечно, это только обрабатывает 8-битный целые числа. –

+1

Он может обрабатывать любые целые числа следующим образом: [n >> i & 1 для i в диапазоне (n.bit_length() - 1, -1, -1)] – mennanov

0

Я делаю это для моей программы, где вы задаете шаблон, чтобы получить свои значения из междунар:

def field(template, value): 
    sums = [int(v) if v.__class__==str else len(bin(v))-2 for v in template] 
    return [(value>> (sum(sums[:i]) if i else 0))&(~(~0<<int(t)) if t.__class__==str else t) for i,t in enumerate(template)] 

как использовать
в шаблоне, укажите Интс, относящиеся к вашему битового размеры:

field([0b1,0b111,0b1111], 204) #>>> [0, 6, 12] 

или вы можете указать битовый размер каждого значения необходимы с помощью строки: (нуб дружественного)

field(['1','3','4'], 204) #>>> [0, 6, 12] 

EDIT: и наоборот: (отдельный код)

field(['1','3','4'], [0, 6, 12]) #>>> 204 
field([0b1,0b111,0b1111], [0,3,9]) #>>> 150 

код:

def field(template, value): 
    res = 0 
    for t, v in zip(template, value)[::-1]: res = (res << (t.bit_length() if t.__class__ is int else int(t)))|v 
    return res 

EDIT2: быстрее код^

Смежные вопросы