Открыть сервисСервис

Побитовая инверсия

Побитовая инверсия (также побитовое отрицание, битовое «НЕ», оператор ~) — это унарная логическая операция над двоичным представлением числа, при которой каждый бит операнда заменяется на противоположный: 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-битного представления.

Связь с другими логическими операциями

Побитовая инверсия является одной из трёх основных битовых операций наряду с побитовым И (&), побитовым ИЛИ (|) и побитовым исключающим ИЛИ (^). Вместе с ними она образует полный набор операций для работы с битами. С помощью комбинации этих операций можно реализовать любую логическую функцию над битами.

Применение в электронике и цифровой технике

В цифровой электронике побитовая инверсия реализуется с помощью логического элемента «НЕ» (инвертора). На уровне микросхем и процессоров операция выполняется за один такт. Инверторы используются в различных цифровых схемах, включая сумматоры, компараторы, мультиплексоры и память.

Источники

  1. Таненбаум Э., Остин Т. Архитектура компьютера. — 6-е изд. — СПб.: Питер, 2013. — 816 с.
  2. Керниган Б., Ритчи Д. Язык программирования Си. — 2-е изд. — М.: Вильямс, 2009. — 304 с.
  3. Страуструп Б. Язык программирования C++. — 4-е изд. — М.: Вильямс, 2012. — 1136 с.
  4. Поляков К.Ю. Программирование на языке Си. — М.: Бином, 2014. — 320 с.
  5. Документация Python: Built-in Types — Bitwise Operations on Integer Types (python.org).
  6. Спецификация языка Java SE 17 — §15.22.1 (Integer Bitwise Operators).
Заметили ошибку или не согласны с информацией в статье? Напишите нам support@bfometr.ru