Побитовые операции — различия между версиями
(→Побитовые сдвиги) |
Penguinni (обсуждение | вклад) (→Применение) |
||
Строка 67: | Строка 67: | ||
====Проверка на то, является ли число степенью двойки==== | ====Проверка на то, является ли число степенью двойки==== | ||
Пусть дано число <tex>x</tex>. Тогда, если результатом выражения <tex>(x\ \&\&\ !(x\ \&\ (x - 1)))</tex> является единица, то число <tex>x</tex> {{---}} степень двойки. | Пусть дано число <tex>x</tex>. Тогда, если результатом выражения <tex>(x\ \&\&\ !(x\ \&\ (x - 1)))</tex> является единица, то число <tex>x</tex> {{---}} степень двойки. | ||
+ | |||
+ | Правая часть выражения <tex>(!(x\ \&\ (x - 1)))</tex> будет равна единице только если число <tex>x</tex> равно <tex>0</tex> или является степенью двойки. Если число <tex>x</tex> является степенью двойки, то в двоичной системе счисления оно представляется следующим образом: <tex>1\underbrace{0\dots0}_{n}</tex>, где <tex>n</tex> {{---}} показатель степени. Соответственно, выражение <tex>(x - 1)</tex> будет иметь вид <tex>\underbrace{1\dots1}_{n}</tex>, и выражение <tex>x\ \&\ (x - 1)</tex> равно <tex>0</tex>. | ||
+ | |||
+ | Операция логического И в данном выражении отсекает тот случай, когда <tex>(x = 0)</tex> и не является степенью двойки, но при этом правая часть выражения <tex>(!(x\ \&\ (x - 1)))</tex> равна единице. | ||
====Определение знака числа==== | ====Определение знака числа==== | ||
− | Поскольку при сдвиге вправо на освобождающиеся позиции устанавливается бит знака, знак числа можно определить | + | Пусть дано число <tex>x</tex>. Поскольку при сдвиге вправо на освобождающиеся позиции устанавливается бит знака, знак числа <tex>x</tex> можно определить, выполнив сдвиг вправо на всю длину переменной: |
<code> | <code> | ||
<font color = green>// в этом и следующих примерах в константе '''CHAR_BIT''' хранится количество битов в одном байте</font> | <font color = green>// в этом и следующих примерах в константе '''CHAR_BIT''' хранится количество битов в одном байте</font> | ||
− | + | ||
− | + | '''if''' x != 0 | |
− | sign = | + | mask = 1 |
− | + | '''else''' | |
− | + | mask = 0 | |
− | + | ||
− | + | sign = mask | (x >> (''sizeof''('''int''') * '''CHAR_BIT''' - 1)) <font color = green>// результатом будет -1, 0, или +1 | |
− | + | // для отрицательного, равного нулю и положительного числа x соответственно</font> | |
</code> | </code> | ||
+ | Используя побитовые операции можно также узнать, различны ли знаки двух переменных <tex>x</tex> и <tex>y</tex>. Если числа имеют различный знак, то результат операции XOR, произведенной над их знаковыми битами, будет единицей. Поэтому неравенство <tex>((x \oplus y) < 0</tex> будет верно в том случае, если числа <tex>x</tex> и <tex>y</tex> разного знака. | ||
====Вычисление модуля числа без использования условного оператора==== | ====Вычисление модуля числа без использования условного оператора==== | ||
+ | Пусть дано число <tex>x</tex>. Тогда | ||
<code> | <code> | ||
mask = x >> ''sizeof''('''int''') * '''CHAR_BIT''' - 1 | mask = x >> ''sizeof''('''int''') * '''CHAR_BIT''' - 1 |
Версия 14:49, 8 марта 2016
Побитовые операции (англ. bitwise operations) — операции, производимые над цепочками битов. Выделяют два типа побитовых операций: логические операции и побитовые сдвиги.
Содержание
Принцип работы
Логические побитовые операции
Битовые операторы И
, ИЛИ , НЕ и исключающее ИЛИ используют те же таблицы истинности, что и их логические эквиваленты.Побитовое И
Побитовое И используется для выключения битов. Любой бит, установленный в
, вызывает установку соответствующего бита результата также в .& | |
---|---|
11001010 11100010 | |
11000010 |
Побитовое ИЛИ
Побитовое ИЛИ используется для включения битов. Любой бит, установленный в
, вызывает установку соответствующего бита результата также в .| | |
---|---|
11001010 11100010 | |
11101010 |
Побитовое НЕ
Побитовое НЕ инвертирует состояние каждого бита исходной переменной.
~ | |
---|---|
11001010 | |
00110101 |
Побитовое исключающее ИЛИ
Исключающее ИЛИ устанавливает значение бита результата в
, если значения в соответствующих битах исходных переменных различны.^ | |
---|---|
11001010 11100010 | |
00101000 |
Побитовые сдвиги
Операторы сдвига двоичном дополнительном коде и необходимо поддерживать знаковый бит).
и сдвигают биты в переменной влево или вправо на указанное число. При этом на освободившиеся позиции устанавливаются нули (кроме сдвига вправо отрицательного числа, в этом случае на свободные позиции устанавливаются единицы, так как числа представляются вСдвиг влево может применяться для умножения числа на два, сдвиг вправо — для деления.
x = 7 // 00000111 (7) x = x >> 1 // 00000011 (3) x = x << 1 // 00000110 (6) x = x << 5 // 11000000 (-64) x = x >> 2 // 11110000 (-16)
В языке программирования Java существует также оператор беззнакового битового сдвига вправо
. При использовании этого оператора на освободившиеся позиции всегда устанавливаются нули.
x = 7 // 00000111 (7) x = x << 5 // 11100000 (-32) x = x >> 2 // 00111000 (56)
Применение
Сложные операции
Проверка на то, является ли число степенью двойки
Пусть дано число
. Тогда, если результатом выражения является единица, то число — степень двойки.Правая часть выражения
будет равна единице только если число равно или является степенью двойки. Если число является степенью двойки, то в двоичной системе счисления оно представляется следующим образом: , где — показатель степени. Соответственно, выражение будет иметь вид , и выражение равно .Операция логического И в данном выражении отсекает тот случай, когда
и не является степенью двойки, но при этом правая часть выражения равна единице.Определение знака числа
Пусть дано число
// в этом и следующих примерах в константе CHAR_BIT хранится количество битов в одном байте if x != 0 mask = 1 else mask = 0 sign = mask | (x >> (sizeof(int) * CHAR_BIT - 1)) // результатом будет -1, 0, или +1 // для отрицательного, равного нулю и положительного числа x соответственно
Используя побитовые операции можно также узнать, различны ли знаки двух переменных
и . Если числа имеют различный знак, то результат операции XOR, произведенной над их знаковыми битами, будет единицей. Поэтому неравенство будет верно в том случае, если числа и разного знака.Вычисление модуля числа без использования условного оператора
Пусть дано число
mask = x >> sizeof(int) * CHAR_BIT - 1 abs = (x + mask)mask // другой способ сделать то же самое: abs = (x mask) - mask
Нахождение минимума и максимума из двух чисел без использования условного оператора
Этот способ корректен только если можно утверждать, что величина
min = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))) max = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1)))
Применение для решения задач
Работа с битовыми масками
Для работы с подмножествами удобно использовать битовые маски. Применяя побитовые операции легко сделать следующее: найти дополнение
, пересечение , объединение множеств, установить бит по номеру , снять бит по номеру .Битовые маски используются, например, при решении некоторых задач[1] динамического программирования.