Побитовая инверсия¶
Побитовая инверсия (также побитовое отрицание, битовое «НЕ», оператор ~) — это унарная логическая операция над двоичным представлением числа, при которой каждый бит операнда заменяется на противоположный: 0 заменяется на 1, а 1 — на 0. Результат побитовой инверсии зависит от разрядности типа данных, используемого для представления числа, и от способа кодирования отрицательных чисел (обычно — дополнительный код).
¶Принцип действия
Побитовая инверсия применяется к каждому биту числа независимо. Если исходное число имеет двоичное представление b_n b_{n-1} ... b_1 b_0, где b_i — значение i-го бита (0 или 1), то результат инверсии — ~b_n ~b_{n-1} ... ~b_1 ~b_0. Операция является унарной, то есть требует только одного операнда.
Например, для 8-битного числа:
- Исходное число:
00001101(десятичное 13) - Результат инверсии:
11110010(десятичное 242 в беззнаковом представлении, или -14 в дополнительном коде).
¶Математическое выражение
Для целого числа x в системе с дополнительным кодом (используемой в большинстве современных компьютеров) побитовая инверсия эквивалентна выражению:
~x = -x - 1
Это соотношение следует из свойств дополнительного кода: инвертирование всех битов числа и прибавление единицы даёт то же самое число с обратным знаком. Поскольку операция ~ выполняет только инвертирование, результатом является -x - 1.
Примеры:
~5= -6 (так как-5 - 1 = -6)~(-3)= 2 (так как-(-3) - 1 = 3 - 1 = 2)~0= -1
¶Зависимость от разрядности
Результат побитовой инверсии существенно зависит от разрядности типа данных, в котором представлено число. Операция выполняется над всеми битами операнда, включая неявные старшие биты.
Например, для 8-битного числа 00000010 (десятичное 2) инверсия даёт 11111101 (десятичное 253 в беззнаковом представлении, или -3 в знаковом). Для 16-битного числа 0000000000000010 (также 2) инверсия даёт 1111111111111101 (десятичное 65533 в беззнаковом представлении, или -3 в знаковом). Таким образом, одно и то же числовое значение, представленное в разных разрядностях, даёт разные результаты при побитовой инверсии.
¶Применение в программировании
¶Установка битов в 1
Побитовая инверсия часто используется в комбинации с другими битовыми операциями для установки определённых битов в 1. Например, чтобы установить бит номер k в 1, можно использовать выражение x | (1 << k). Если нужно установить все биты, кроме одного, используется маска, полученная инверсией: x | ~(1 << k).
¶Сброс битов в 0
Для сброса бита в 0 применяется маска с инверсией: x & ~(1 << k). Здесь 1 << k создаёт число с единицей в позиции k, а инверсия превращает его в число с нулём в этой позиции и единицами во всех остальных. Побитовое И с такой маской сбрасывает только указанный бит.
¶Проверка битов
Для проверки значения бита используется выражение (x & (1 << k)) != 0. Инверсия может применяться для проверки, что бит равен 0: (x & (1 << k)) == 0 эквивалентно (~x & (1 << k)) != 0.
¶Работа с масками
Маски — это числа, используемые для выделения или изменения определённых битов. Побитовая инверсия позволяет инвертировать маску, что полезно для операций «исключающего ИЛИ» (XOR) и для создания масок, которые выделяют все биты, кроме указанных.
¶Оптимизация вычислений
В некоторых алгоритмах побитовая инверсия используется для замены арифметических операций. Например, выражение x = -x - 1 может быть заменено на x = ~x, что на некоторых архитектурах выполняется быстрее. Однако современные компиляторы обычно оптимизируют такие выражения автоматически.
¶Примеры в языках программирования
¶Си и C++
Оператор ~ применяется к целым типам (int, unsigned int, char, long и т.д.). Результат — целое число того же типа, что и операнд (с учётом целочисленного продвижения). Пример: ``c unsigned char a = 13; // 00001101 unsigned char b = ~a; // 11110010 = 242 ``
¶Python
В Python оператор ~ также выполняет побитовую инверсию, но с учётом бесконечной точности целых чисел. Результат — отрицательное число в дополнительном коде, но формально Python не имеет фиксированной разрядности. Пример: ``python a = 13 b = ~a # -14 ` Для получения беззнакового результата (например, для 8-битного представления) используют маску: ~a & 0xFF`.
¶Java
В Java оператор ~ работает с целыми типами (byte, short, int, long). Результат — число того же типа. Пример: ``java int a = 13; int b = ~a; // -14 ``
¶JavaScript
JavaScript использует 32-битные знаковые целые для побитовых операций, хотя числа хранятся как 64-битные числа с плавающей точкой. Оператор ~ сначала преобразует операнд в 32-битное целое, затем выполняет инверсию. Пример: ``javascript let a = 13; let b = ~a; // -14 ``
¶Особенности и подводные камни
¶Знаковость и беззнаковость
При работе с беззнаковыми типами (unsigned int в C/C++) побитовая инверсия даёт положительное число, которое может быть очень большим. Например, для 8-битного беззнакового числа 0 инверсия даёт 255. При работе со знаковыми типами результат может быть отрицательным.
¶Целочисленное продвижение
В языках C и C++ перед выполнением побитовой инверсии операнды меньшего размера (char, short) продвигаются до типа int. Это может привести к неожиданным результатам, если не учитывать разрядность. Например, unsigned char a = 0; ~a даёт результат типа int со значением -1, а не 255.
¶Бесконечная точность в Python
В Python, где целые числа имеют произвольную точность, ~x всегда даёт -x - 1. Для получения результата в фиксированной разрядности необходимо применять маску, например ~x & 0xFFFFFFFF для 32-битного представления.
¶Связь с другими логическими операциями
Побитовая инверсия является одной из трёх основных битовых операций наряду с побитовым И (&), побитовым ИЛИ (|) и побитовым исключающим ИЛИ (^). Вместе с ними она образует полный набор операций для работы с битами. С помощью комбинации этих операций можно реализовать любую логическую функцию над битами.
¶Применение в электронике и цифровой технике
В цифровой электронике побитовая инверсия реализуется с помощью логического элемента «НЕ» (инвертора). На уровне микросхем и процессоров операция выполняется за один такт. Инверторы используются в различных цифровых схемах, включая сумматоры, компараторы, мультиплексоры и память.
¶Источники
- Таненбаум Э., Остин Т. Архитектура компьютера. — 6-е изд. — СПб.: Питер, 2013. — 816 с.
- Керниган Б., Ритчи Д. Язык программирования Си. — 2-е изд. — М.: Вильямс, 2009. — 304 с.
- Страуструп Б. Язык программирования C++. — 4-е изд. — М.: Вильямс, 2012. — 1136 с.
- Поляков К.Ю. Программирование на языке Си. — М.: Бином, 2014. — 320 с.
- Документация Python: Built-in Types — Bitwise Operations on Integer Types (python.org).
- Спецификация языка Java SE 17 — §15.22.1 (Integer Bitwise Operators).