Несмотря на то, что Python не считается подходящим языком для низкоуровневого программирования, инструменты для этого у него всё же есть. Один из таких инструментов — побитовые (или битовые) операторы.
Побитовые операторы в Python предназначены для изменения строк с двоичным кодом, что может понадобиться для работы с криптографическими алгоритмами, драйверами различных устройств или, например, с сетевой инфраструктурой. Также они могут пригодиться для изменения графики низкого уровня и для любых других задач, где требуется выполнять различные действия с двоичным кодом.
Результатом действия побитовых операторов в Python является изменение объекта на уровне битов путем нескольких типов логических операций с двоичным кодом. Эти операции мы и рассмотрим в данной статье.
Миграция в то самое облако
безопасно и с гарантией результата.
Предоставим грант до 1 000 000 ₽ на облачную
инфраструктуру и возьмем на себя весь процесс.
Побитовый вывод натуральных чисел
Поскольку мы будем работать с двоичным кодом, причем преимущественно с целыми числами, давайте сначала научимся выводить эти числа в нужном нам виде. Это делается очень просто:
Вот мы и получили бинарное представление числа 5. Впрочем, совсем ли бинарное? На самом деле 5 здесь — это последние три цифры (101), а код 0b используется в Python для вывода чисел в бинарном виде (есть и -0b для отрицательных значений). Теперь мы можем вывести любое число в двоичном коде, а вот так будет выглядеть ноль и первая десятка:
Из этого ряда понятен принцип битового представления чисел: единицы последовательно заменяют нули, а когда все значения достигают 1, добавляется новый разряд. Досчитаем до 15:
Четвертый разряд исчерпан (заполнен единицами), поэтому далее в дело вступает пятый, и числа 16 и 17 будут записаны уже так:
Таким образом, двоичный код организован строго по законам математики: три разряда битов будет у чисел от 4 до 7, четвертый добавляется для чисел от 8 до 15, пять разрядов будет у чисел с 16 до 31, шесть — с 32 до 63, семь — с 64 до 127 и т. д. То есть новый разряд добавляется при очередном умножении на два. Это полезно знать при сравнении операндов с разной разрядностью: в этом случае у операнда с меньшим числом разрядов можно добавить соответствующее число нулей сразу после 0b.
Типы основных битовых операторов Python
Теперь мы готовы оперировать битами, используя логику следующих инструментов:
- & (AND)
- | (OR)
- ^ (XOR)
- ~ (NOT)
- Сдвиги
& (AND, И)
Логика работы: при сравнении двух бит (в одном и том же разряде) & выдает 1 (то есть бит будет скопирован), если бит есть в обоих сравниваемых операндах, и 0, если это условие не выполняется (то есть бит отсутствует хотя бы в одном из операндов). Схематически работу & можно представить так:
Это самое жесткое условие, когда бит возвращается (выдается 1) только в случае, если он был в обоих операндах. Теперь примеры:
Потому что:
Добавляем тройке третий разряд для удобства представления и видим, что только средние биты присутствуют у обоих значений (по 1 в каждом числе), поэтому возвращается такое число: 0b010, а это 2.
Потому что:
Интересный результат, который получился потому, что совпадающие биты оказались ровно на тех же позициях, что и в представлении первого числа.
А теперь примеры посложнее, попрактикуемся с числами с разным количеством разрядов:
| (OR, ИЛИ)
Логика работы: при сравнении двух бит | выдает 1 (бит будет скопирован), если бит есть хотя бы в одном из сравниваемых операндах, и 0, если он отсутствует в обоих. Схематически работу | можно представить так:
Таким образом, бит будет возвращен во всех случаях, кроме одного: когда в обоих сравниваемых операндах нули. Примеры:
Бит не копируется только во втором разряде (справа), поскольку там нули у обоих операндов, в результате возвращается 13.
И задачи посложнее, с уже знакомыми цифрами, но совершенно иными результатами:
^ (XOR, исключающее ИЛИ)
Логика работы: при сравнении двух бит ^ выдает 1 (бит будет скопирован), если сравниваемые операнды различаются, и 0, если они одинаковы. Схематически работу ^ можно представить так:
Как видим, оператору XOR неважно, сравниваются две единицы или два нуля: в обоих случаях бит возвращен не будет: бит возвращается только при сравнении разных значений. Примеры:
Во всех разрядах, кроме крайнего левого, операнды не совпали, поэтому в этих случаях были возвращены биты, то есть интерпретатор выдал единицы.
Несколько примеров с операндами с разным количеством разрядов:
~ (NOT, НЕ)
~ не сравнивает значения, а переворачивает биты в целочисленных значениях. При этом учтите, что положительные числа будут преобразованы в отрицательные со сдвигом на единицу, и наоборот. Работает это так:
Побитовые сдвиги влево и вправо
Левый сдвиг обозначается символами << , при этом слева пишется изменяемое число, а справа от оператора указывается количество бит, на которое выполняется сдвиг.
Сдвинули 1 на 1 бит и получили 2, потому что:
то есть, единица переместилась на одну позицию влево. А если переместить на две?
Да, получается 4, так как:
Нетрудно догадаться, что даст сдвиг единицы на 3 позиции:
Вот еще пара примеров с раскладкой по битам:
Правый сдвиг обозначается символами >>, и точно так же слева пишется изменяемое число, а справа от оператора указывается количество бит, на которое выполняется сдвиг. Это обратная операция, поэтому:
Подготовили для вас выгодные тарифы на облачные серверы
477 ₽/мес
657 ₽/мес
Практическое применение в программировании
- Одна из областей IT, где активно используются битовые операции (в особенности сдвиги) — криптография. Сдвиговые операции позволяют изменять значения данных так, что без наличия ключей, хранящих первоначальные значения, дешифрование становится невозможным.
- Следующая область применения битовых операций: сетевые технологии, где действия над битами необходимы для проверки соответствия адресов и подсетей.
- А практика побитовых операций
&и|поможет вам лучше понять принцип работы операторовandиorв Python и то, как работают любые другие программы, где используется Булева логика, основанная на значениях True (1) и False (0).
