Поразрядные операции с числами Python

При работе с числами в программировании мы часто сталкиваемся с различными операциями, которые могут быть выполнены над отдельными битами чисел. Эти операции, известные как поразрядные операции, играют важную роль в различных аспектах программирования, начиная от простого шифрования до более сложных математических операций. Давайте взглянем на некоторые из них.

Двоичное представление чисел

В двоичной системе каждое число представлено разрядами, которые могут быть либо 0, либо 1. Например, число 5 в двоичной системе будет представлено как 101. Для вывода числа в двоичной системе в Python используется спецификатор 0b. Также можно определять числа прямо в двоичной форме с помощью префикса 0b. Это основа для понимания поразрядных операций.
Пример:

number = 5
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 - в десятичной системе

Логические операции

Логические операции выполняются над отдельными разрядами числа. В 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 фактически аналогично - (x+1). Например:

x = 5
y = ~x
print(f"y: {y}") # -6

В Python операция инверсии числа (~x) инвертирует каждый бит числа x. Для лучшего понимания, представьте, что числа в компьютере представлены в двоичной системе, то есть как последовательности нулей и единиц.
Давайте рассмотрим пример с числом 5. В двоичном виде оно записывается как 0000 0101. Используя операцию инверсии (~), каждый бит этого числа инвертируется: каждый ноль становится единицей, и каждая единица - нулем. Таким образом, после инверсии получается число 1111 1010.
Теперь возникает вопрос: почему результат -6?
В Python и многих других языках программирования числа представляются в двоичном дополнительном коде. В этой системе отрицательные числа представлены с использованием дополнительного кода. Дополнительный код отрицательного числа получается путем инвертирования битов этого числа и последующим прибавлением 1.
После инверсии битов числа 5 мы получаем 1111 1010. Теперь, чтобы получить дополнительный код этого числа, добавим к нему 1:

1111 1010 # Результат инверсии битов числа 5
+ 1
------------
1111 1011 # Результат

Таким образом, получившийся результат 1111 1011 в двоичном дополнительном коде представляет собой -6 в десятичном представлении.
Таким образом, операция инверсии (~x) в Python фактически аналогична выражению -(x+1).

Операции сдвига

Операции сдвига также производятся над разрядами чисел. Сдвиг может происходить вправо и влево.
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

Понимание поразрядных операций с числами является важным аспектом в программировании. Эти операции могут быть использованы для решения различных задач, начиная от простых операций с битами до сложных математических алгоритмов.

Обсуждение закрыто.