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

Последнее обновление: 11.01.2022

Особый класс операций представляют поразрядные операции. Они выполняются над отдельными разрядами чисел типа 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
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850