Я немного смущен оператором ~
. Код идет ниже:
a = 1
~a #-2
b = 15
~b #-16
Как работает ~
?
Я думал, ~a
будет примерно таким:
0001 = a
1110 = ~a
почему бы и нет?
Я немного смущен оператором ~
. Код идет ниже:
a = 1
~a #-2
b = 15
~b #-16
Как работает ~
?
Я думал, ~a
будет примерно таким:
0001 = a
1110 = ~a
почему бы и нет?
Вы совершенно правы. Это артефакт двух дополнений целочисленного представления.
В 16 бит 1 представляется как 0000 0000 0000 0001
. Перевернутый, вы получаете 1111 1111 1111 1110
, который равен -2. Аналогично, 15 0000 0000 0000 1111
. Перевернутый, вы получаете 1111 1111 1111 0000
, который равен -16.
В общем случае ~n = -n - 1
Оператор '~' определяется как: "Побитовая инверсия x определяется как - (x + 1), она применима только к целым числам". Python Doc - 5.5
Важная часть этого предложения состоит в том, что это связано с "целыми числами" (также называемыми целыми числами). Ваш пример представляет 4-битное число.
'0001' = 1
Integer диапазон 4-битного числа равен -8.0..7. С другой стороны, вы можете использовать "целые числа без знака", которые не включают отрицательное число, а диапазон для вашего 4-битного номера будет "0..15".
Поскольку Python работает с целыми числами, поведение, о котором вы описали, ожидается. Целые числа представлены с использованием двух дополнений. В случае 4-битного номера это выглядит следующим образом.
7 = '0111'
0 = '0000'
-1 = '1111'
-8 = '1000'
Python использует 32-битное целочисленное представление, если у вас 32-разрядная ОС. Вы можете проверить наибольшее целое число с помощью:
sys.maxint # (2^31)-1 for my system
Если вы хотите, чтобы целое число без знака вернуло вам 4-битное число, вы должны замаскировать.
'0001' = a # unsigned '1' / integer '1'
'1110' = ~a # unsigned '14' / integer -2
(~a & 0xF) # returns 14
Если вы хотите получить беззнаковый 8-разрядный диапазон номеров (0..255), просто используйте:
(~a & 0xFF) # returns 254
Похоже, я нашел более простое решение, которое делает то, что вам нужно:
uint8: x ^ 0xFF<br>
uint16: x ^ 0xFFFF<br>
uint32: x ^ 0xFFFFFFFF<br>
uint64: x ^ 0xFFFFFFFFFFFFFFFF
Вы также можете использовать unsigned ints (например, из пакета numpy) для достижения ожидаемого поведения.
>>> import numpy as np
>>> bin( ~ np.uint8(1))
'0b11111110'