Записать число в нужный бит c. Битовые операции. _______________побитовое исключающее ИЛИ _______________

Admin 09.02.2015

Доброго дня уважаемые друзья!
Приветствую Вас на сайте

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

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

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

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

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



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

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

Или присвойте нескольким переменным одно значение с одним утверждением. Символ подчеркивания также разрешен. Имена не должны начинаться с цифры. Как показывает последний пример, некоторые слова зарезервированы как ключевые слова на языке, и они не могут использоваться как имена переменных.

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

Чтобы мы не путались с выражениями «битовая операция» и «побитовая операция», запомним, что выполнение битовой операции — это выполнение побитовых операций с отдельными битами, и в дальнейшем я буду просто писать — «битовая операция» или «логическая операция».

Кроме того, существуют определенные наборы имен, которые, хотя и не являются языковыми ключевыми словами, зарезервированы по той или иной причине. Пока что просто избегайте использования имен, начинающихся с символа подчеркивания. В любое время внутри программы, в которой вы указываете значение явно, вместо обращения к переменной или какой-либо другой форме данных, это значение называется литералом. В приведенном выше примере инициализации 3 является литералом. Пока, однако, вы, вероятно, не должны слишком беспокоиться о гексагоне.

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

Кроме того, читая техническую литературу вы наверняка столкнетесь с терминами «унарная операция» и «бинарная операция» .
Унарная операция — операция над одним операндом (Битовая операция «НЕ»).
Бинарная операция — операция с двумя операндами (Битовые операции «И», «ИЛИ», «ИСКЛЮЧАЮЩЕЕ ИЛИ»)

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

Некоторые считают, что это очень плохая практика, если мы используем ее для хранения персонажа, а не небольшого числа, поскольку если кто-то читает ваш код, большинство читателей вынуждены искать, какой символ соответствует номеру 97 в кодирования. Важно отметить, что символы для цифр представлены иначе, чем их соответствующее число, т.е. 1 не равно Короче, любая отдельная запись, заключенная в «одинарные кавычки».

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

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

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

Он также хранит реальные числа, но это только одно машинное слово в размере. Типы с двойным и плавающим типами очень похожи. Его размер обычно составляет два машинных слова или 8 байтов на большинстве машин. Различие между поплавками и удвоениями было сделано из-за разных размеров двух типов. В настоящее время, когда память более свободна, вам не нужно экономить память, как это: может быть, лучше использовать двойники последовательно. Его синтаксис. Два выражения выше возвращают размер объекта и тип, указанный в байтах.

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

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

роме инвертирования состояния битов регистра, битовая операция НЕ, применяется для нахождения дополнительного кода числа (из положительного числа — сделать отрицательное). Для этого необходимо число проинвертировать и к полученному результату прибавить единицу .

Чтобы использовать модификатор, просто объявите переменную с типом данных и соответствующими модификаторами. Когда используется определитель констант, объявленная переменная должна быть инициализирована при объявлении. Тогда не разрешается изменять. Хотя идея переменной, которая никогда не изменяется, может показаться нецелесообразной, есть веские причины использовать константу. Во-первых, многие компиляторы могут выполнять небольшую оптимизацию по данным, когда знают, что данные никогда не изменятся.

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

Например, вы можете написать программу для продуктового магазина. Эта сложная программа имеет тысячи и тысячи строк кода. Программист решает представить стоимость банка кукурузы, в настоящее время 99 центов, в качестве буквального кода. Теперь предположим, что стоимость банка кукурузы меняется до 89 центов. Программист должен теперь войти и вручную изменить каждую запись в 99 центов. Хотя это не так уж и важно, учитывая функцию «глобального поиска-замены» многих текстовых редакторов, рассмотрите еще одну проблему: стоимость банки зеленого цвета бобы также изначально 99 центов.

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

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

Чтобы надежно изменить цену, вы должны посмотреть на каждое появление числа. Эта функциональность приблизительно эквивалентна, хотя один метод может быть полезен в одном случае, за другим. Существует также другой способ избежать магических чисел. Он также включает препроцессор, в отличие от компилятора. Когда вы пишете программы, вы можете создать так называемый макрос, поэтому, когда компьютер читает ваш код, он заменит все экземпляры слова указанным выражением.

Он игнорирует структуру вашей программы, заменяя текст повсюду, что может быть выгодным в некоторых обстоятельствах, но может быть источником проблемных ошибок. В разделе «Основные понятия» была введена концепция области. Важно пересмотреть различия между локальными типами и глобальными типами и как объявлять переменные каждого из них. Чтобы объявить локальную переменную, вы поместите объявление в начале блока, к которому предназначена переменная, которая является локальной. Чтобы объявить глобальную переменную, объявите переменную вне любого блока.

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

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


— для проверки бита на 0 или 1, оно же чтение конкретного бита (если результат равен 0, значит бит равен 0, иначе бит равен 1):

Если переменная является глобальной, ее можно читать и записывать из любой точки вашей программы. Глобальные переменные не считаются хорошей практикой программирования, и их следует избегать, когда это возможно. Они препятствуют чтению кода, создают конфликты именования, теряют память и могут создавать ошибки для отслеживания ошибок. Чрезмерное использование глобалов обычно является признаком лени или плохого дизайна. Однако, если есть ситуация, когда локальные переменные могут создавать более тупой и нечитаемый код, нет никакого позора в использовании глобальных переменных.


— проверка четности числа (четность — способность числа делиться на два)
У чётных чисел первый бит (самый правый) всегда равен нулю, а в нечётных единице:

Общим недоверием является то, что единственной целью является сохранение переменной в памяти. Когда вы объявляете функцию или глобальную переменную статичной, она становится внутренней. Когда вы объявляете локальную переменную как статическую, она создается так же, как любая другая переменная. Однако, когда переменная выходит за пределы области видимости, переменная остается в памяти, сохраняя ее значение. Переменная остается в памяти до завершения программы. Хотя это поведение похоже на поведение глобальных переменных, статические переменные по-прежнему подчиняются правилам области видимости и поэтому не могут быть доступны за пределами их объема.

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

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

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

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

Статические вары - это хороший способ реализации инкапсуляции, термин объектно-ориентированного мышления, который фактически означает, что не допускается внесение изменений в переменную, за исключением вызовов функций. Запуск программы выше приведет к следующему результату.

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

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

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


Область действия - Локальная для блока, в котором он объявлен. Время жизни. Значение сохраняется между различными вызовами функций. Вариант ключевого слова. Обязательно использовать ключевое слово. Область действия - глобальное время жизни - значение сохраняется до завершения выполнения программы. Вариант ключевого слова - необязательный, если объявлен вне всех функций.

Если вы считаете, что это похоже на то, что вы делали все время, когда вы объявляете переменную, вы правы: все объявленные элементы внутри блока неявно «автоматически». Особенности автоматических переменных. Значение по умолчанию - Значение мусора. Область действия - Локально к блоку, в котором он определен. Значение сохраняется, пока элемент управления остается в блоке. Опциональность ключевого слова.

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

— определения равенства регистров (если результат равен нулю, значит содержимое регистров равно, иначе — не равно):

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

Необязательно. В некоторых случаях программисту необходимо выйти за рамки этого - то есть на более глубоком уровне, где реализуется важность бит. Чтобы кодировать, декодировать или сжимать файлы, мы должны извлекать данные на уровне бит. Побитовые операции быстрее и ближе к системе и иногда оптимизируют программу до хорошего уровня. Мы все знаем, что 1 байт состоит из 8 бит, и любое целое число или символ могут быть представлены с использованием бит в компьютерах, которые мы называем его двоичной формой или в форме основания 2.

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

В системе команд микроконтроллеров AVR есть несколько битовых операций, которые трудно однозначно отнести к разделу только логических операций, они вполне могут найти себе место и в разделе арифметических операций (вернее, они там и находятся). Таких операций три:
— логический сдвиг
— арифметический сдвиг
— циклический сдвиг через бит переноса
Мы рассмотрим только операции, относящиеся к логическому сдвигу , а операции арифметического и циклического сдвига — в статьях по командам микроконтроллера.
Битовые операции сдвига , относящиеся к логическому сдвигу :
— логический сдвиг влево
— логический сдвиг вправо

В манипуляции бит используются разные побитовые операции. Эти битовые операции работают с отдельными битами битовых шаблонов. Операции с битами выполняются быстро и могут быть использованы для оптимизации временной сложности. Некоторые обычные операторы бит.

_______________поразрядная инверсия ~ _______________

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

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

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



в основном используется как арифметическая операция для целочисленного умножения на 2.
На рисунке вверху показана выполненная два раза операция «логический сдвиг влево» — произведено два сдвига содержимого байта влево.
При этом:
— старшие биты, (выделены красным цветом) уходят в небытие (теряются)
— освободившиеся места младших битов заполняются «0» (выделены синим цветом)

Зачем нужны побитовые логические операции

Давайте обсудим некоторые алгоритмы, основанные на побитовых операциях. Есть и особый случай. Та же проблема может быть решена с помощью манипуляции с битами. Свойства для чисел, которые являются степенями 2, состоит в том, что они имеют один и только один бит, установленный в их двоичном представлении. Если число не равно нулю и не равно двум, оно будет иметь 1 в более чем одном месте.

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

Давайте посмотрим что получилось:
— первоначальное значение регистра 0000 0101 = 5 (в десятичной системе)
— первый сдвиг влево — получаем 0000 1010 = 10
— второй сдвиг влево — получаем 0001 0100 = 20
— а если произвести третий сдвиг — получим 0010 1000 = 40
Как видите, в результате каждого сдвига регистра, происходит умножение на два. Таким образом если нам надо умножить содержимое регистра на 8 (2 в степени 3), нам надо произвести 3 сдвига влево. А если надо умножить на 16 (2 в степени 4) — то 4 сдвига.
При этом надо учитывать, что число на которое можно умножить содержимое регистра должно быть равно «2 в степени n».

Это был пример сдвига как арифметической операции. Применение сдвига как логической операции — тут огромный простор для фантазии. Для примера — записываем в регистр 0000 0001, выводим содержимое в любой порт к выводам которого подсоединены светодиоды, — загорается первый светодиод, производим сдвиг — первый гаснет, зажигается второй (логическая единица переместилась на один разряд), результат — бегущий огонь на выходе.

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

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


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

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

Первоначальное число, записанное в регистр — 00100101 = 37 (десятичное)
— первый сдвиг — получаем 0001 0010 = 18
— второй сдвиг — получаем 0000 1001 = 9
При логическом сдвиге вправо происходит деление целочисленного числа на 2. При этом, как вы видите, если число нечетное (37), то при делении на 2 оно как-бы округляется в меньшую сторону (18). При этом надо учитывать, что число на которое можно разделить содержимое регистра должно быть равно «2 в степени n».

Предыдущие статьи:

2. Системы счисления: десятичная, двоичная и шестнадцатиричная

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

Введение

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

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

  • | (Побитовое ИЛИ (OR)),
  • & (Побитовое И (AND)),
  • ^ (Исключающее ИЛИ (XOR)),
  • ~ (Побитовое отрицание (NOT)),
  • << (Побитовый сдвиг влево),
  • >> (Побитовый сдвиг вправо).

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

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

  1. Некоторые побитовые операторы похожи на операторы, с которыми вы наверняка знакомы (&&, ||). Это потому, что они на самом деле в чем-то похожи. Тем не менее, путать их ни в коем случае нельзя.
  2. Большинство битовых операций являются операциями составного присваивания.

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

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

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

A 0 0 1 0 0 1 1 0
B 0 0 1 1 0 1 0 1
A | B 0 0 1 1 0 1 1 1

В итоге мы получаем 110111 2 , или 55 10 .

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

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

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

A 0 0 1 0 0 1 1 0
B 0 0 1 1 0 1 0 1
A & B 0 0 1 0 0 1 0 0

Как результат, получаем 100100 2 , или 36 10 .

С помощью побитового оператора И можно проверить, является ли число четным или нечетным. Для целых чисел, если младший бит равен 1, то число нечетное (основываясь на преобразовании двоичных чисел в десятичные). Зачем это нужно, если можно просто использовать %2 ? На моем компьютере, например, &1 выполняется на 66% быстрее. Довольно неплохое повышение производительности, скажу я вам.

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

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

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

A 1 0 0 0 1 0 1 0
B 0 0 1 0 1 0 1 1
A ^ B 1 0 1 0 0 0 0 1

… 10100001 2 , или 160 10

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

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

String msg = "This is a message" ;

char message = msg . toCharArray () ;

String key = ".*)" ;

String encryptedString = new String () ;

for (int i = 0 ; i & lt ; message . length ; i ++ ) {

encryptedString += message [ i ] ^ key . toCharArray () [ i % key . length () ] ;

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

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

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

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

A 0 0 1 1 0 1 0 0
~A 1 1 0 0 1 0 1 1

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

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

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

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

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

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

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

A 0 1 1 0 1 1 0 1
~A 1 0 0 1 0 0 1 0
~A+1 1 0 0 1 0 0 1 1

Представленным выше методом мы получаем -109 в дополнительном коде.
Только что было представлено очень упрощенное объяснение дополнительного кода, и я настоятельно советую вам детальнее изучить эту тему.

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

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

A 1 0 1 1 0 1 0 0
A<<2 1 1 0 1 0 0 0 0

Интересной особенностью сдвига влево на N позиций является то, что это эквивалентно умножению числа на 2 N . Таким образом, 43<<4 == 43*Math.pow(2,4) . Использование сдвига влево вместо Math.pow обеспечит неплохой прирост производительности.

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

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

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

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

Вывод

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