Что такое битовый сдвиг

О битовых операциях

Авторизуйтесь

О битовых операциях

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

В этой статье я расскажу вам о том, как работают битовые операции. С первого взгляда они могут показаться вам чем-то сложным и бесполезным, но на самом деле это совсем не так. В этом я и попытаюсь вас убедить.

Введение

Побитовые операторы проводят операции непосредственно на битах числа, поэтому числа в примерах будут в двоичной системе счисления.

Я расскажу о следующих побитовых операторах:

Битовые операции изучаются в дискретной математике, а также лежат в основе цифровой техники, так как на них основана логика работы логических вентилей — базовых элементов цифровых схем. В дискретной математике, как и в цифровой технике, для описания их работы используются таблицы истинности. Таблицы истинности, как мне кажется, значительно облегчают понимание битовых операций, поэтому я приведу их в этой статье. Их, тем не менее, почти не используют в объяснениях побитовых операторов высокоуровневых языков программирования.

О битовых операторах вам также необходимо знать:

Побитовое ИЛИ (OR)

Побитовое ИЛИ действует эквивалентно логическому ИЛИ, но примененному к каждой паре битов двоичного числа. Двоичный разряд результата равен 0 только тогда, когда оба соответствующих бита в равны 0. Во всех других случаях двоичный результат равен 1. То есть, если у нас есть следующая таблица истинности:

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

38 | 53 будет таким:

A00100110
B00110101
A | B00110111

Побитовое И (AND)

Побитовое И — это что-то вроде операции, противоположной побитовому ИЛИ. Двоичный разряд результата равен 1 только тогда, когда оба соответствующих бита операндов равны 1. Другими словами, можно сказать, двоичные разряды получившегося числа — это результат умножения соответствующих битов операнда: 1х1 = 1, 1х0 = 0. Побитовому И соответствует следующая таблица истинности:

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Пример работы побитового И на выражении 38 & 53:

A00100110
B00110101
A & B00100100

Исключающее ИЛИ (XOR)

Разница между исключающим ИЛИ и побитовым ИЛИ в том, что для получения 1 только один бит в паре может быть 1:

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Например, выражение 138^43 будет равно…

A10001010
B00101011
A ^ B10100001

С помощью ^ можно поменять значения двух переменных (имеющих одинаковый тип данных) без использования временной переменной.

Также с помощью исключающего ИЛИ можно зашифровать текст. Для этого нужно лишь итерировать через все символы, и ^ их с символом-ключом. Для более сложного шифра можно использовать строку символов:

Исключающее ИЛИ не самый надежный способ шифровки, но его можно сделать частью шифровального алгоритма.

Побитовое отрицание (NOT)

Побитовое отрицание инвертирует все биты операнда. То есть, то что было 1 станет 0, и наоборот.

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Вот, например, операция

Результатом будет 20310

При использовании побитового отрицания знак результата всегда будет противоположен знаку исходного числа (при работе со знаковыми числами). Почему так происходит, узнаете прямо сейчас.

Дополнительный код

Здесь мне стоит рассказать вам немного о способе представления отрицательных целых чисел в ЭВМ, а именно о дополнительном коде (two’s complement). Не вдаваясь в подробности, он нужен для облегчения арифметики двоичных чисел.

Главное, что вам нужно знать о числах, записанных в дополнительном коде — это то, что старший разряд является знаковым. Если он равен 0, то число положительное и совпадает с представлением этого числа в прямом коде, а если 1 — то оно отрицательное. То есть, 10111101 — отрицательное число, а 01000011 — положительное.

Чтобы преобразовать отрицательное число в дополнительный код, нужно инвертировать все биты числа (то есть, по сути, использовать побитовое отрицание) и добавить к результату 1.

Например, если мы имеем 109:

A01101101

A+1

10010011

Побитовый сдвиг влево

Побитовые сдвиги немного отличаются от рассмотренных ранее битовых операций. Побитовый сдвиг влево сдвигает биты своего операнда на N количество битов влево, начиная с младшего бита. Пустые места после сдвига заполняются нулями. Происходит это так:

Побитовый сдвиг вправо

Как вы могли догадаться, >> сдвигает биты операнда на обозначенное количество битов вправо.

Если операнд положительный, то пустые места заполняются нулями. Если же изначально мы работаем с отрицательным числом, то все пустые места слева заполняются единицами. Это делается для сохранения знака в соответствии с дополнительным кодом, объясненным ранее.

Вывод

Итак, теперь вы знаете больше о битовых операциях и не боитесь их. Могу предположить, что вы не будете использовать >>1 при каждом делении на 2. Тем не менее, битовые операции неплохо иметь в своем арсенале, и теперь вы сможете воспользоваться ими в случае надобности или же ответить на каверзный вопрос на собеседовании.

Источник

Побитовые операторы и операторы сдвига (справочник по C#)

Следующие операторы выполняют побитовые операции или операции сдвига с операндами целочисленных или символьных типов:

Побитовые операции и операции сдвига никогда не вызывают переполнение и дают одинаковые результаты в проверенных и непроверенных контекстах.

Оператор побитового дополнения

создает побитовое дополнение своего операнда путем инвертирования каждого бита:

Можно также использовать символ

для объявления методов завершения. Дополнительные сведения см. в разделе Методы завершения.

Оператор сдвига влево сдвигает левый операнд влево на количество битов, определенное правым операндом.

Операция сдвига влево отбрасывает старшие биты, которые находятся за пределами диапазона типа результата, и задает позиции пустых битов низкого порядка, равные нулю, как показано в следующем примере:

Сведения о том, как правый операнд оператора определяет величину сдвига, см. в разделе Величина смещения операторов сдвига.

Оператор сдвига вправо >>

Операция сдвига вправо удаляет младшие разряды, как показано в следующем примере:

Позиции пустых битов высокого порядка задаются с учетом типа левого операнда следующим образом:

Сведения о том, как правый операнд оператора >> определяет величину сдвига, см. в разделе Величина смещения операторов сдвига.

Оператор логического И &

Оператор & вычисляет побитовое логическое И целочисленных операндов:

Для операндов типа bool оператор & вычисляет логическое И по своим операндам. Унарный оператор & является оператором AddressOf.

Оператор логического исключения ИЛИ ^

Оператор ^ вычисляет побитовое логическое исключающее ИЛИ, также известное как побитовое логическое XOR, своих целочисленных операндов:

Для операндов типа bool оператор ^ вычисляет логическое исключающее ИЛИ по своим операндам.

Оператор логического ИЛИ |

Оператор | вычисляет побитовое логическое ИЛИ своих целочисленных операндов:

Для операндов типа bool оператор | вычисляет логическое ИЛИ по своим операндам.

Составное присваивание

Для бинарного оператора op выражение составного присваивания в форме

за исключением того, что x вычисляется только один раз.

В следующем примере показано использование составного присваивания с побитовыми операторами и операторами сдвига:

Приоритет операторов

Следующий список упорядочивает побитовые операторы и операторы сдвига по приоритету, от высокого до низкого:

Порядок вычисления, определяемый приоритетом операторов, можно изменить с помощью скобок ( () ).

Полный список операторов C#, упорядоченный по уровню приоритета, можно найти в разделе Приоритет операторов статьи Операторы C#.

Величина смещения операторов сдвига

Для выражений x и x >> count фактическая величина сдвига зависит от типа x следующим образом:

В следующем примере продемонстрировано такое поведение.

Как показано в предыдущем примере, результат операции сдвига может быть ненулевым, даже если значение правого операнда больше числа битов в левом операнде.

Логические операторы перечисления

Побитовые логические операторы обычно используются с типом перечисления, который определяется с помощью атрибута Flags. Дополнительные сведения см. в разделе Типы перечислений как битовые флаги в статье Типы перечислений.

Возможность перегрузки оператора

Определяемый пользователем тип может перегружать операторы

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

Источник

Битовые операции

Логические битовые (побитовые) операции
Битовые операции сдвига

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

И еще, регистр общего назначения (R0. R31) я буду обозначать аббревиатурой РОН.

Битовые (побитовые) логические операции

Битовая операция НЕ:

Если бит равен «1», то после выполнения операции он будет равен «0». И наоборот, если бит равен «0», то после выполнения операции он будет равен «1». (операция выполняется одновременно над всеми битами РОН). В качестве операнда может использоваться только РОН

Обозначается знаком «

Дополнительный код, как и прямой и обратный коды — наиболее распространённые способы представления десятичных чисел в двоичном коде. Это вопрос будет рассмотрен в отдельной статье.

Битовая операция И:

Если оба соответствующих бита операндов равны 1, результирующий двоичный разряд равен 1; если же хотя бы один бит из пары равен 0, результирующий двоичный разряд равен 0. В качестве операндов могут использоваться два РОН или РОН и константа (число, записанное в памяти МК)

Обозначается знаком «&»

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Практическое применение:
— для сброса конкретного бита (битов) в ноль:

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг
— для проверки бита на 0 или 1, оно же чтение конкретного бита (если результат равен 0, значит бит равен 0, иначе бит равен 1):

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Битовая операция ИЛИ

Если оба соответствующих бита операндов равны 0, двоичный разряд результата равен 0; если же хотя бы один бит из пары равен 1, двоичный разряд результата равен 1. В качестве операндов могут использоваться два РОН или РОН и константа

Обозначается знаком «|» (вертикальная палочка)

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Битовая операция ИСКЛЮЧАЮЩЕЕ ИЛИ

Результат действия выполнения операции равен 1, если число складываемых единичных битов нечётно и равен 0, если чётно. В качестве операндов могут использоваться только РОН

Обозначается знаком «^»

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Практическое применение:
— для инвертирования битов регистра по маске

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Битовые операции сдвига

Логический сдвиг влево

При логическом сдвиге влево происходит сдвиг всех разрядов регистра влево на одну позицию, старший бит (самый левый) при этом теряется, а в младший (самый правый) записывается 0.

Обозначается знаком «

Логический сдвиг вправо

При логическом сдвиге вправо происходит сдвиг всех разрядов регистра вправо на одну позицию, младший бит (самый правый) при этом теряется, а в старший (самый левый) записывается 0

Обозначается знаком «>>»

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг

Логический сдвиг вправо используется как арифметическая операция для целочисленного деления на 2.

Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвигЧто такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвигЧто такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвигЧто такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг Что такое битовый сдвиг. Смотреть фото Что такое битовый сдвиг. Смотреть картинку Что такое битовый сдвиг. Картинка про Что такое битовый сдвиг. Фото Что такое битовый сдвиг(29 голосов, оценка: 4,97 из 5)

Источник

Битовые операции

Введение

Я зык Си иногда называют макроассемблером за его тягу к железу. Если не использовать оптимизацию, можно даже примерно оценить, в какие конструкции на ассемблере преобразуется код программы. Простота и минимализм языка (простоту языка не путать с простотой программирования на языке) привели к тому, что на многих платформах си остаётся единственным высокоуровневым языком программирования. Без обзора побитовых операций, конечно, изучения языка было бы неполным.

Побитовые операции, как понятно из названия, позволяют оперировать непосредственно с битами. Большое количество примеров использования побитовых операций можно найти, например, в книге Генри Уоррена «Алгоритмические трюки для программистов». Здесь мы рассмотрим только сами операции и примитивные алгоритмы.

Побитовые И, ИЛИ, НЕ, исключающее ИЛИ

ЗАМЕЧАНИЕ: здесь и далее в примерах используются 8-битные числа для упрощения записи. Всё это верно и для любых других чисел.

Н апомню для начала, что логические операции И, ИЛИ, исключающее ИЛИ и НЕ могут быть описаны с помощью таблиц истинности

Логический оператор ИЛИ

XYX OR Y
000
011
101
111
Логический оператор исключающее ИЛИ

XYX XOR Y
000
011
101
110

В побитовых (bit-wise) операциях значение бита, равное 1, рассматривается как логическая истина, а 0 как ложь. Побитовое И (оператор &) берёт два числа и логически умножает соответствующие биты. Например, если логически умножить 3 на 8, то получим 0

Так как в двоичном виде 3 в виде однобайтного целого представляет собой

Первый бит переменной c равен логическому произведению первого бита числа a и первого бита числа b. И так для каждого бита.

00000011
00001000 ↓↓↓↓↓↓↓↓
00000000

00011111
00010001 ↓↓↓↓↓↓↓↓
00010001

Побитовое произведение чисел 35 и 15 равно 3.

00100011
00001111 ↓↓↓↓↓↓↓↓
00000011

Аналогично работает операция побитового ИЛИ (оператор |), за исключением того, что она логически суммирует соответствующие биты чисел без переноса.

00001111
00001011 ↓↓↓↓↓↓↓↓
00001111

00100001
00001011 ↓↓↓↓↓↓↓↓
00101011

Побитовое отрицание (оператор

) работает не для отдельного бита, а для всего числа целиком. Оператор инверсии меняет ложь на истину, а истину на ложь, для каждого бита. Например,

Исключающее ИЛИ (оператор ^) применяет побитово операцию XOR. Например, для чисел

Иногда логические операторы && и || путают с операторами & и |. Такие ошибки могут существовать в коде достаточно долго, потому что такой код в ряде случаев будет работать. Например, для чисел 1 и 0. Но так как в си истиной является любое ненулевое значение, то побитовое умножение чисел 3 и 4 вернёт 0, хотя логическое умножение должно вернуть истину.

Операции побитового сдвига

О пераций сдвига две – битовый сдвиг влево (оператор >). Битовый сдвиг вправо сдвигает биты числа вправо, дописывая слева нули. Битовый сдвиг влево делает противоположное: сдвигает биты влево, дописывая справа нули. Вышедшие за пределы числа биты отбрасываются.

Например, сдвиг числа 5 влево на 2 позиции

Сдвиг числа 19 вправо на 3 позиции

00010011 >> 3 == 00000010

Независимо от архитектуры (big-endian, или little-endian, или middle-endian) числа в двоичном виде представляются слева направо, от более значащего бита к менее значащему. Побитовый сдвиг принимает два операнда – число, над которым необходимо произвести сдвиг, и число бит, на которое необходимо произвести сдвиг.

Так как сдвиг вправо (>>) дописывает слева нули, то для целых чисел операция равносильна целочисленному делению пополам, а сдвиг влево умножению на 2. Произвести битовый сдвиг для числа с плавающей точкой без явного приведения типа нельзя. Это вызвано тем, что для си не определено представление числа с плавающей точкой. Однако можно переместить число типа float в int, затем сдвинуть и вернуть обратно

Но мы, конечно же, получим не 5.0f, а совершенно другое число.

Особенностью операторов сдвига является то, что они могут по-разному вести себя с числами со знаком и без знака, в зависимости от компилятора. Действительно, отрицательное число обычно содержит один бит знака. Когда мы будем производить сдвиг влево, он может пропасть, число станет положительным. Однако, компилятор может сделать так, что сдвиг останется знакопостоянным и будет проходить по другим правилам. То же самое и для сдвига вправо.

В данном случае при первом сдвиге всё работает, как и задумано, потому что число без знака. Во втором случае компилятор VSE2013 оставляет знак. Однако если посмотреть на представление этого числа, как беззнакового, сдвиг происходит по другим правилам, с сохранением самого левого бита. В последней строчке, если привести число со знаком к числу без знака, то произойдёт обычный сдвиг, и мы получим в результате положительное число.

Побитовые операторы и операторы сдвига не изменяют значения числа, возвращая новое. Они также как и арифметические операторы, могут входить в состав сложного присваивания

Примеры

1. Напишем функции, которые позволяют определять и изменять определённый бит числа

Для того, чтобы узнать, какой бит (1 или 0) стоит на позиции n, воспользуемся логическим умножением.

Пусть имеется число 9

Нужно узнать, выставлен ли бит на позиции 3 (начиная с нуля). Для этого умножим его на число, у которого все биты равны нулю, кроме третьего:

00001001 & 00001000 = 00001000

Теперь узнаем значение бита в позиции 6

00001001 & 01000000 = 00000000

Таким образом, если мы получаем ответ, равный нулю, то на искомой позиции находится ноль, иначе единица. Чтобы получить число, состоящее из нулей с одним битом на нужной позиции, сдвинем 1 на нужное число бит влево.

Заметьте, что в функции условие записано так

Потому что без скобок сначала будет вычислено равенство нулю и только потом выполнено умножение.

Функцию можно упростить

Функция, которая выставляет бит на n-й позиции в единицу.

Известно, что логическое сложение любого бита с 1 будет равно 1. Так что для установки n-го бита нужно логически сложить число с таким, у которого все биты, кроме нужного, равны нулю. Как получить такое число, уже рассмотрено.

Функция, которая устанавливает бит на n-й позиции в ноль.

Для этого нужно, чтобы все биты числа, кроме n-го, не изменились. Умножим число на такое, у которого все биты равны единице, кроме бита под номером n. Например

0001011 & 1110111 = 0000011

Чтобы получить такую маску, сначала создадим число с нулями и одной единицей, а потом инвертируем его.

Функция, изменющая значение n-го бита на противоположное.

Для этого воспользуемся функцией исключающего или: применим операцию XOR к числу, которое состоит из одних нулей и одной единицы на месте нужного бита.

Битовые флаги

Расммотрим синтетический пример. Пусть у нас есть три логические переменные, и нам нужно вывести определённое значение в зависимости от всех этих переменных сразу. Очевидно, что может быть 2 3 возможных вариантов. Запишем это условие в виде ветвления:

Мы получили 8 ветвей. Пусть теперь нам понадобилось добавить ещё одно условие. Тогда число ветвей удвоится, и программа станет ещё сложней для понимания и отладки. Перепишем пример.

Если каждое из наших логичесих значений сдвинуть на своё число бит влево и логически сложить, то мы получим свою уникальную комбинацию бит в зависимоти от значений a, b и c:

Используем этот подход к нашей задаче и заменим ветвеление на switch:

Этот метод очень часто используется для назначения опций функций в разных языках программирования. Каждый флаг принимает своё уникальное название, а их совместное значение как логическая сумма всех используемых флагов. Например, библиотека fcntl:

Здесь флаг O_RDWR рaвен

00000000000000000000001000000000

и O_APPEND

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *