Битовые операции в Python: как использовать битовую маску

5065584

Я мастерю себе генетическую оптимизацию на Python 2.6, отчего у меня встала задача "скрестить" два числа: старшие биты от одного и младшие - отдругого. Понятно, что это надо делать битовой маской. Я честно думаю, что у меня 32-битное число. Делаю маску для старших битов
 pos=res_pos=random.uniform(1,31)
mask=0x7fffffff >> res_pos

так что скрещивание выглядит как
 child=val2 & mask + val1 & (~mask) 

И тут меня подстерегает пакость. Оказывается, в Python ~0b0000111111111111=-0b001000000000000, а не 0b1111000000000000, как я мог бы ожидать. Почему? И как достичь искомого результата?

Dimon89

Вынести код в модуль на с++? ;)

vall

~mask -> 2**32-mask ?

marat7256

В питоне нет операции побитового отрицания?

Plok2008

Может не надо суммировать, а продолжать работать с побитными операциями?
child=(val2 & mask) | (val1 & (~mask

khachin

У питона 0b0000111111111111 все равно остается int'ом длиной 12 бит, а арифметика проводится по принципу ~x = -1-x
Поэтому вместо ~mask для 16-битной записи пишется 65535^mask (или (2**16-1)^mask, или если угодно 0b1111111111111111^mask)
>>> mask = 0b111111111111
>>> mask.__class__
<type 'int'>
>>> mask.bit_length
12
>>> mask^65535
61440
>>> bin(_)
'0b1111000000000000'

Полагаю, что "скрещивание" можно определить формулами:
child = mask & val2 + 0xffffffff ^ mask) & val1)
child = mask & val2 + (0xffffffff - mask & val1)
child = mask & val2 + (2**32 + ~mask & val1)

Если хочется реально оперировать битами, то придется импортировать внешние модули. Для питона есть C'шное расширение bitarray.

5065584

Спасибо, ваш рецепт про
 non_mask=0xFFFFFFFF^mask 

сделал то, чего и хотелось.

5065584

И вам спасибо за совет

beluchy

эээ, а в чем собственно проблема?

In [686]: "%04x %04x"%(0x0fff & 0xabcd, ~0x0fff & 0xabcd)
Out[686]: '0bcd a000'

khachin

Я уже потом обратил внимание, в действительности проблема была в исходной формуле. Операции & и + выполняются последовательно слева направо, поэтому достаточно было "заскобить" второе слагаемое. Или, как предложил , оставаться в побитовых операциях (меньше риск возникновения ошибки).
Я вот до сего дня не знал:
>>> mask = 0x7fffffff
>>> val=300
>>> ~mask == 0xffffffff^mask
False
>>> ~mask&val == (0xffffffff^mask)&val
True

Не было надобности работать с битами.

bleyman

Эм, в Питоне битовая арифметика работает правильно, и если у тебя что-то выходит не то, это значит, что ты её делаешь неправильно.
Например, вовсе не нужно закладываться на битность компьютера, вместо 0xFFFFFFFFF можно спокойно использовать -1, все биты, _все_ биты там будут правильные.

ppplva

Верно, там просто бесконечное число бит. И идиотская с виду запись -0b... нужна для того, чтобы представить бесконечное число ведущих единиц.
-x = ~x + 1
Оставить комментарий
Имя или ник:
Комментарий: