Особый класс операций представляют поразрядные операции. Они выполняются над отдельными разрядами чисел типа int. Но чтобы понять природу поразрядных операций, надо понимать что вообще представляет число в двоичном представление.
При двоичной системе каждый разряд числа может иметь только два значения - 0 и 1. Например, 0 в десятичной системе также будет равен 0 в двоичной системе, а 1 в десятичной системе будет соответствовать 1 в двоичной системе. Следующее число в десятичной системе - 2 в двоичной системе будет соответствовать 10. То есть, когда мы к 1 прибавляем 1, то результатом будет 10. И так далее.
Например, 5 в двоичном представлении 101 и имеет три разряда. Для вывода десятичного числа в двоичной системе можно применять спецификатор
0b
:
number = 5 # в двоичной форме 101 print(f"number = {number:0b}") # number = 101
Без указания спецификатора функция print()
выводит число в десятичной системе.
При этом Python позволяет сразу определять число в двоичной форме. Для этого число в двоичной форме указывается после префикса 0b:
number = 0b101 # определяем число в двоичной форме print(f"number = {number:0b}") # number = 101 print(f"number = {number}") # number = 5 - в десятичной системе
Еще несколько примеров сопоставления между двоичной и десятичной системами:
number1 = 1 # в двоичной системе 0b1 number2 = 2 # в двоичной системе 0b10 number3 = 3 # в двоичной системе 0b11 number4 = 4 # в двоичной системе 0b100 number5 = 5 # в двоичной системе 0b101 number6 = 6 # в двоичной системе 0b110
Логические операции выполняются над отдельными разрядами числа. В Python есть следующие логические операции:
&(логическое умножение)
Умножение производится поразрядно, и если у обоих операндов значения разрядов равно 1, то операция возвращает 1, иначе возвращается число 0. Например:
x1 = 2 # 010 y1 = 5 # 101 z1 = x1 & y1 print(f"z1 = {z1}") # z1 = 0 x2 = 4 # 100 y2 = 5 # 101 z2 = x2 & y2 print(f"z2 = {z2}") # z2 = 4 print(f"z2 = {z2:0b}") # z2 = 100
В первом случае у нас два числа 2 и 5. 2 в двоичном виде представляет число 010, а 5 - 101. Поразрядно умножим числа (0*1, 1*0, 0*1) и в итоге получим 000.
Во втором случае у нас вместо двойки число 4, у которого в первом разряде 1, так же как и у числа 5, поэтому в итоге получим (1*1, 0*0, 0 *1) = 100, то есть число 4 в десятичном формате.
| (логическое сложение)
Похоже на логическое умножение, операция также производится по двоичным разрядам, но теперь возвращается единица, если хотя бы у одного числа в данном разряде имеется единица. Например:
x1 = 2 # 010 y1 = 5 # 101 z1 = x1|y1 # 111 print(f"z1 = {z1}") # z1 = 7 print(f"z1 = {z1:0b}") # z1 = 111 x2 = 4 # 100 y2 = 5 # 101 z2 = x2 | y2 # 101 print(f"z2 = {z2}") # z2 = 5 print(f"z2 = {z2:0b}") # z2 = 101
^ (логическое исключающее ИЛИ)
Если значения текущего разряда у обоих чисел разные, то возвращается 1, иначе возвращается 0. Также эту операцию называют XOR. Например:
x = 9 # 1001 y = 5 # 0101 z = x ^ y # 1100 print(f"z = {z}") # z = 12 print(f"z = {z:0b}") # z = 1100
Здесь число 9 в двоичной форме равно 1001. Число 5 равно 0101. Операция XOR дает следующий результат: 1^0, 0^1, 0^0, 1^1. Здесь мы видим, что первые два разряда чисел содержат разные значения, поэтому первые два разряда получат значение 1. А последние два разряда чисел содержат одинаковые значения, поэтому последние два разряда получат значение 0. Таким образом, мы получаем число 1100 или 12 в десятичной системе.
нередко данную операцию применяют для простого шифрования:
x = 45 # Значение, которое надо зашифровать - в двоичной форме 101101 key = 102 # Пусть это будет ключ - в двоичной форме 1100110 encrypt = x ^ key # Результатом будет число 1001011 или 75 print(f"Зашифрованное число: {encrypt}") decrypt = encrypt ^ key # Результатом будет исходное число 45 print(f"Расшифрованное число: {decrypt}")
Также можно применять эту операцию для обмена значений чисел:
x = 9 # 1001 y = 5 # 0101 x = x ^ y y = x ^ y x = x ^ y print(f"x = {x}") # x = 5 print(f"y = {y}") # y = 9
~(инверсия)
Инвертирует число. Выражение ~x
фактически аналогично -(x+1)
. Например:
x = 5 y = ~x; print(f"y: {y}") # -6
Операции сдвига также производятся над разрядами чисел. Сдвиг может происходить вправо и влево.
x<<y
- сдвигает число x влево на y разрядов. Например, 4<<1
сдвигает число 4 (которое в двоичном представлении 100) на один разряд влево, то есть в итоге получается 1000 или число 8 в десятичном представлении.
x>>y
- сдвигает число x вправо на y разрядов. Например, 16>>1 сдвигает число 16 (которое в двоичном представлении 10000) на один разряд вправо, то есть в итоге получается 1000 или число 8 в десятичном представлении.
Таким образом, если исходное число, которое надо сдвинуть в ту или другую строну, делится на два, то фактически получается умножение или деление на два. Поэтому подобную операцию можно использовать вместо непосредственного умножения или деления на два. Например:
a = 16 # в двоичной форме 10000 b = 2 c = a << b # Сдвиг числа 10000 влево на 2 разряда, равно 1000000 или 64 в десятичной системе print(c) #64 d = a >> b #Сдвиг числа 10000 вправо на 2 разряда, равно 100 или 4 в десятичной системе print(d) #4
При этом числа, которые участвую в операциях, необязательно должны быть кратны 2::
a = 22 # в двоичной форме 10110 b = 2 c = a << b # Сдвиг числа 10110 влево на 2 разряда, равно 1011000 или 88 в десятичной системе print(c) # 88 d = a >> b # Сдвиг числа 10110 вправо на 2 разряда, равно 101 или 5 в десятичной системе print(d) # 5