побитовая операция унарный ~ (инвертировать) - PullRequest
51 голосов
/ 02 сентября 2011

Я немного сбит с толку оператором ~. Код идет ниже:

a = 1
~a  #-2
b = 15
~b  #-16

Как работает ~?

Я думал, ~a будет что-то вроде:

0001 = a
1110 = ~a 

почему бы и нет?

Ответы [ 5 ]

48 голосов
/ 02 сентября 2011

Вы совершенно правы. Это артефакт двоичного дополнения целочисленного представления.

В 16 битах 1 представляется как 0000 0000 0000 0001. Инвертированный, вы получите 1111 1111 1111 1110, что равно -2. Точно так же 15 - это 0000 0000 0000 1111. Инвертированный, вы получите 1111 1111 1111 0000, что составляет -16.

В общем ~n = -n - 1

28 голосов
/ 09 октября 2012

Оператор '~' определяется как: «Побитовая инверсия x определяется как - (x + 1). Она применяется только к целым числам.» Python Doc - 5.5

Важной частью этого предложения является то, что это связано с «целыми числами» (также называемыми целыми числами).В вашем примере представлено 4-битное число.

'0001' = 1 

Целочисленный диапазон 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
6 голосов
/ 26 октября 2017

Похоже, я нашел более простое решение, которое делает то, что нужно:

uint8: x ^ 0xFF
uint16: x ^ 0xFFFF
uint32: x ^ 0xFFFFFFFF
uint64: x ^ 0xFFFFFFFFFFFFFFFF
3 голосов
/ 05 декабря 2016

Вы также можете использовать беззнаковые целые (например, из numpy пакета) для достижения ожидаемого поведения.

>>> import numpy as np
>>> bin( ~ np.uint8(1))
'0b11111110'
0 голосов
/ 04 октября 2018

Оператор унарной инверсии Python ~ x = - (x + 1), и это равно так же, как переключение каждого бита в памяти:

например,

>>> 0b110    # an integer defined with a binary literal
# 0|1,1,0    = in sign|magnitude form
# +|4,2,0    = each bit's contribution to the int
# +1*(4+2+0) =>
6            

>>> bin(~0b110) # get the binary representation of inverted 0b110
# 1|001         = each bit simply inverted (invert sign bit too)
# -|4+2+0 +1    = each bit's contribution to the int, ‡See note
# -1*(4+2+0+1)  = -7    (the answer we want that represents each bit flipped)
# -0b111        = binary representation of -7
-0b111          = it resembles 1|111 but it in memory it is actually 1|001

-0b111 - это 1|001 в памяти.Вы не должны интерпретировать представление двоичных чисел -ve как то, что хранится в памяти, в отличие от положительного двоичного числа.

‡ Примечание. Отрицательные числа в двоичном количестве учитываются в обратном порядке, поэтому каждая позиция -ve бита учитывается только при составлении int , если оно равно 0, и вы должны добавить -1 к конечному результату:

# in-memory  = int  (displayed as)
1|11..111    = -1   (-0b1)
1|11..110    = -2   (-0b10)
1|11..101    = -3   (-0b11)
1|11..100    = -4   (-0b100)
# and so on...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...