Рассмотрим этот код:
x = 1 # 0001
x << 2 # Shift left 2 bits: 0100
# Result: 4
x | 2 # Bitwise OR: 0011
# Result: 3
x & 1 # Bitwise AND: 0001
# Result: 1
Я могу понимать арифметические операторы в Python (и других языках), но я никогда не понимал достаточно хорошо «побитовые» операторы. В приведенном выше примере (из книги Python) я понимаю левый сдвиг, но не два других.
Кроме того, для чего на самом деле используются побитовые операторы? Буду признателен за несколько примеров.
Ответы:
Поразрядные операторы - это операторы, которые работают с многобитными значениями, но концептуально по одному за раз.
AND
равен 1, только если оба его входа равны 1, в противном случае - 0.OR
равен 1, если один или оба его входа равны 1, в противном случае - 0.XOR
равен 1, только если ровно один из его входов равен 1 , в противном случае - 0.NOT
равен 1, только если его вход равен 0, в противном случае - 0.Их часто лучше всего показать в виде таблиц истинности. Возможности ввода находятся сверху и слева, результирующий бит является одним из четырех (два в случае НЕ, поскольку он имеет только один ввод) значений, показанных на пересечении вводов.
Одним из примеров является то, что если вам нужны только младшие 4 бита целого числа, вы И его с 15 (двоичный 1111), поэтому:
Нулевые биты в 15 в этом случае эффективно действуют как фильтр, заставляя биты в результате также быть нулевыми.
Кроме того,
>>
и<<
часто включаются как побитовые операторы, и они «сдвигают» значение соответственно вправо и влево на определенное количество бит, отбрасывая биты, которые катятся на конце, к которому вы смещаетесь, и вводя нулевые биты в другой конец.Так, например:
Обратите внимание, что левый сдвиг в Python необычен тем, что он не использует фиксированную ширину, при которой отбрасываются биты - в то время как многие языки используют фиксированную ширину в зависимости от типа данных, Python просто расширяет ширину для обслуживания дополнительных бит. Чтобы получить поведение отбрасывания в Python, вы можете следовать за левым сдвигом с побитовым сдвигом,
and
например, в 8-битном значении, сдвигающем влево четыре бита:Имея это в виду, другой пример побитовых операторов: если у вас есть два 4-битных значения, которые вы хотите упаковать в 8-битное, вы можете использовать все три своих оператора (
left-shift
,and
иor
):& 15
Операция будет убедиться , что оба значения имеют только младшие 4 бита.<< 4
4-битный сдвиг влево для переходаval1
к верхним 4 битам 8-битного значения.|
Просто объединяет эти два вместе.Если
val1
7 иval2
4:источник
Типичное использование:
|
используется для установки определенного бита в 1&
используется для проверки или очистки определенного битаУстановите бит (где n - номер бита, а 0 - младший бит):
unsigned char a |= (1 << n);
Немного проясни:
unsigned char b &= ~(1 << n);
Немного переключить:
unsigned char c ^= (1 << n);
Протестируйте немного:
unsigned char e = d & (1 << n);
Возьмем, к примеру, случай из вашего списка:
x | 2
используется для установки бита 1x
в 1x & 1
используется для проверки того,x
равен ли бит 0 значения 1 или 0источник
Одним из наиболее распространенных способов использования побитовых операций является анализ шестнадцатеричных цветов.
Например, вот функция Python, которая принимает строку типа String
#FF09BE
и возвращает кортеж ее значений Red, Green и Blue.Я знаю, что есть более эффективные способы добиться этого, но я считаю, что это действительно краткий пример, иллюстрирующий как сдвиги, так и побитовые логические операции.
источник
Думаю, что вторая часть вопроса:
Решено лишь частично. Это мои два цента по этому поводу.
Побитовые операции в языках программирования играют фундаментальную роль при работе с большим количеством приложений. Почти все низкоуровневые вычисления должны выполняться с использованием такого рода операций.
Во всех приложениях, которым необходимо отправлять данные между двумя узлами, например:
компьютерные сети;
телекоммуникационные приложения (сотовые телефоны, спутниковая связь и т. д.).
На более низком уровне связи данные обычно отправляются так называемыми кадрами . Фреймы - это просто строки байтов, которые отправляются по физическому каналу. Эти кадры обычно содержат фактические данные плюс некоторые другие поля (закодированные в байтах), которые являются частью того, что называется заголовком . Заголовок обычно содержит байты, которые кодируют некоторую информацию, относящуюся к состоянию связи (например, с флагами (битами)), счетчиками кадров, кодами исправления и обнаружения ошибок и т. Д. Для получения переданных данных в кадре и для построения кадры для отправки данных, которые вам понадобятся для выполнения побитовых операций.
В общем, при работе с такими приложениями доступен API, поэтому вам не нужно разбираться со всеми этими деталями. Например, все современные языки программирования предоставляют библиотеки для подключений к сокетам, поэтому вам на самом деле не нужно создавать фреймы связи TCP / IP. Но подумайте о хороших людях, которые запрограммировали эти API для вас, им наверняка приходилось иметь дело с конструкцией фреймов; использование всевозможных поразрядных операций для перехода от низкоуровневой связи к высокоуровневой.
В качестве конкретного примера представьте, что кто-то дает вам файл, содержащий необработанные данные, которые были захвачены непосредственно телекоммуникационным оборудованием. В этом случае, чтобы найти фреймы, вам нужно будет прочитать необработанные байты в файле и попытаться найти какие-то слова синхронизации, побитно просканировав данные. После определения слов синхронизации вам нужно будет получить фактические кадры и при необходимости ПЕРЕМЕСТИТЬ их (и это только начало истории), чтобы получить фактические данные, которые передаются.
Еще одно совершенно другое семейство приложений низкого уровня - это когда вам нужно управлять оборудованием с помощью некоторых (древних) портов, таких как параллельные и последовательные порты. Эти порты управляются установкой нескольких байтов, и каждый бит этих байтов имеет определенное значение с точки зрения инструкций для этого порта (см., Например, http://en.wikipedia.org/wiki/Parallel_port ). Если вы хотите создать программное обеспечение, которое что-то делает с этим оборудованием, вам потребуются побитовые операции для преобразования инструкций, которые вы хотите выполнить, в байты, которые понимает порт.
Например, если у вас есть какие-то физические кнопки, подключенные к параллельному порту для управления другим устройством, это строка кода, которую вы можете найти в программном приложении:
Надеюсь, это поможет.
источник
Надеюсь, это проясняет эти два:
источник
x & 1
не иллюстрирует эффект так хорошо, как еслиx & 2
бы.Считайте 0 ложным, а 1 истинным. Затем побитовое и (&) и или (|) работают так же, как и обычные и, за исключением того, что они обрабатывают все биты в значении одновременно. Обычно вы увидите, что они используются для флагов, если у вас есть 30 параметров, которые можно установить (скажем, как стили рисования в окне), вы не хотите передавать 30 отдельных логических значений для установки или отключения каждого из них, поэтому вы используете | для объединения параметров в одно значение, а затем вы используете &, чтобы проверить, установлена ли каждая опция. Этот стиль передачи флагов широко используется OpenGL. Поскольку каждый бит является отдельным флагом, вы получаете значения флагов по степени двойки (например, числа, у которых установлен только один бит) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) степень двойки сообщает вам, какой бит установлен, если флаг установлен.
Также обратите внимание, что 2 = 10, поэтому x | 2 равно 110 (6), а не 111 (7) Если ни один из битов не перекрывается (что в данном случае верно) | действует как дополнение.
источник
Я не видел этого, упомянутого выше, но вы также увидите, что некоторые люди используют сдвиг влево и вправо для арифметических операций. Сдвиг влево на x эквивалентен умножению на 2 ^ x (если он не переполняется), а сдвиг вправо эквивалентен делению на 2 ^ x.
Недавно я видел людей, использующих x << 1 и x >> 1 для удвоения и уменьшения вдвое, хотя я не уверен, просто ли они пытаются быть умными или действительно есть явное преимущество перед обычными операторами.
источник
Наборы
Наборы можно комбинировать с помощью математических операций.
|
объединяет два набора, чтобы сформировать новый, содержащий элементы в любом из них.&
получает элементы только в обоих.-
получает элементы в первом наборе, но не во втором.^
получает элементы в любом наборе, но не в обоих.Попробуй сам:
Результат:
источник
Этот пример покажет вам операции для всех четырех 2-битных значений:
Вот один из примеров использования:
источник
Другой распространенный вариант использования - это управление / тестирование прав доступа к файлам. См. Модуль статистики Python: http://docs.python.org/library/stat.html .
Например, чтобы сравнить разрешения файла с желаемым набором разрешений, вы можете сделать что-то вроде:
Я передаю результаты как логические, потому что меня волнует только правда или ложь, но было бы полезно распечатать значения bin () для каждого из них.
источник
not bool((mode ^ desired_mode) & 0777)
. Или (легче понять)not (mode & 0777) ^ desired_mode == 0
. И оставит только интересные биты, XOR проверит, что все желаемые биты установлены. Явное== 0
сравнение более значимо, чемbool()
.setWindowFlags
. Пример:setWindowFlags(SplashScreen | WindowStaysOnTopHint)
. Я все еще нахожу это запутанным, так как кажется, что вы устанавливаете переключатель в положение «включено», поэтому в таком случае он кажется более интуитивным для «и».Битовые представления целых чисел часто используются в научных вычислениях для представления массивов истинно-ложной информации, поскольку побитовая операция выполняется намного быстрее, чем итерация по массиву логических значений. (В языках более высокого уровня может использоваться идея битового массива.)
Хороший и довольно простой пример этого - общее решение игры Ним. Взгляните на код Python на странице Википедии . Он широко использует побитовое исключающее или,
^
.источник
Может быть лучший способ найти, где элемент массива находится между двумя значениями, но, как показывает этот пример, & здесь работает, а и - нет.
источник
Я не видел, чтобы это упоминалось, этот пример покажет вам десятичную операцию (-) для 2-битных значений: AB (только если A содержит B)
эта операция необходима, когда в нашей программе содержится глагол, представляющий биты. иногда нам нужно добавить биты (как указано выше), а иногда нам нужно удалить биты (если глагол содержит, то)
с python: 7 & ~ 4 = 3 (удалите из 7 биты, которые представляют 4)
с python: 1 & ~ 4 = 1 (удалите из 1 биты, которые представляют 4 - в этом случае 1 не содержит 4) ..
источник
Хотя манипулирование битами целого числа полезно, часто для сетевых протоколов, которые могут быть указаны с точностью до бита, может потребоваться манипулирование более длинными последовательностями байтов (которые нелегко преобразовать в одно целое число). В этом случае полезно использовать библиотеку битовых цепочек, которая позволяет выполнять побитовые операции с данными - например, можно импортировать строку 'ABCDEFGHIJKLMNOPQ' как строку или как шестнадцатеричный и сдвинуть ее бит (или выполнить другие побитовые операции):
источник
следующие побитовые операторы: & , | , ^ и ~ возвращают значения (в зависимости от их ввода) точно так же, как логические элементы влияют на сигналы. Вы можете использовать их для имитации схем.
источник
Чтобы перевернуть биты (например, дополнение / инвертирование до 1), вы можете сделать следующее:
Поскольку значение ExORed со всеми единицами приводит к инверсии, для заданной разрядности вы можете использовать ExOR, чтобы инвертировать их.
источник