Подтвердить что ты не робот

Побитовая операция и использование

Рассмотрим этот код:

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) я понимаю сдвиг влево, но не два других.

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

4b9b3361

Ответ 1

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

  • AND равен 1, только если оба его входа равны 1, иначе 0.
  • OR - 1, если один или оба его входа равны 1, иначе 0.
  • XOR равен 1, только если один из его входов равен 1, в противном случае 0.
  • NOT равен 1, только если его значение равно 0, в противном случае оно равно 0.

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

AND | 0 1     OR | 0 1     XOR | 0 1    NOT | 0 1
----+-----    ---+----     ----+----    ----+----
 0  | 0 0      0 | 0 1       0 | 0 1        | 1 0
 1  | 0 1      1 | 1 1       1 | 1 0

Например, если вам нужны только младшие 4 бита целого числа, вы И его с 15 (двоичный код 1111), поэтому:

    201: 1100 1001
AND  15: 0000 1111
------------------
 IS   9  0000 1001

Нулевые биты в 15 в этом случае эффективно действуют как фильтр, заставляя биты в результате также иметь нулевое значение.

Кроме того, >> и << часто включаются как побитовые операторы, и они "сдвигают" значение соответственно справа и слева на определенное количество бит, отбрасывая биты, которые свертывают конец, который вы смещаете в направлении и подачи нулевых бит на другом конце.

Итак, например:

1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000

Обратите внимание, что сдвиг влево в Python необычен тем, что он не использует фиксированную ширину, где бит отбрасывается, - хотя многие языки используют фиксированную ширину на основе типа данных, Python просто расширяет ширину, чтобы обслуживать дополнительные биты. Чтобы получить отбрасывающее поведение в Python, вы можете следовать сдвигу влево с поразным AND, например, в 8-битном значении, сдвигающем левые четыре бита:

bits8 = (bits8 << 4) & 255

С учетом этого еще один пример побитовых операторов - если у вас есть два 4-битных значения, которые вы хотите упаковать в 8-разрядный, вы можете использовать все три из ваших операторов (left-shift, AND и OR):

packed_val = ((val1 & 15) << 4) | (val2 & 15)
  • Операция & 15 гарантирует, что оба значения имеют только более низкие 4 бита.
  • << 4 - это 4-битный сдвиг влево, чтобы переместить val1 в верхние 4 бита 8-битного значения.
  • | просто объединяет эти два вместе.

Если val1 равно 7 и val2 равно 4:

                val1            val2
                ====            ====
 & 15 (and)   xxxx-0111       xxxx-0100  & 15
 << 4 (left)  0111-0000           |
                  |               |
                  +-------+-------+
                          |
| (or)                0111-0100

Ответ 2

Одно типичное использование:

| используется для установки определенного бита в 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 используется для установки бит 1 x в 1

x & 1 используется для проверки, если бит 0 из x равен 1 или 0

Ответ 3

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

Одним из наиболее распространенных применений побитовых операций является разбор шестнадцатеричных цветов.

Например, здесь Python функция, которая принимает строку типа #FF09BE и возвращает кортеж своих красных, зеленых и синих значения.

def hexToRgb(value):
    # Convert string to hexadecimal number (base 16)
    num = (int(value.lstrip("#"), 16))

    # Shift 16 bits to the right, and then binary AND to obtain 8 bits representing red
    r = ((num >> 16) & 0xFF)

    # Shift 8 bits to the right, and then binary AND to obtain 8 bits representing green
    g = ((num >> 8) & 0xFF)

    # Simply binary AND to obtain 8 bits representing blue
    b = (num & 0xFF)
    return (r, g, b)

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

Ответ 4

Надеюсь, это прояснит эти два вопроса:

x | 2

0001 //x
0010 //2

0011 //result = 3

x & 1

0001 //x
0001 //1

0001 //result = 1

Ответ 5

Подумайте, что 0 - false, а 1 - как истинный. Затем побитовые и (&) и/или (|) работают так же, как и обычные, и/или только за исключением того, что все биты в значении сразу. Как правило, вы увидите, что они используются для флагов, если у вас есть 30 параметров, которые можно установить (например, стили рисования в окне), которые вы не хотите передавать в 30 отдельных логических значениях, чтобы установить или отключить их, чтобы вы использовали | для объединения опций в одно значение, а затем вы используете и проверяете, установлен ли каждый параметр. Этот стиль прохождения флага сильно используется OpenGL. Поскольку каждый бит является отдельным флагом, вы получаете значения флага по степеням двух (или числа, которые имеют только один бит) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) power of two сообщает вам, какой бит установлен, если флаг включен.

Также обратите внимание на 2 = 10, так что x | 2 равно 110 (6) не 111 (7) Если ни один из битов не перекрывается (что в этом случае истинно) | действует как дополнение.

Ответ 6

Я не видел упоминания выше, но вы также увидите, что некоторые люди используют сдвиг влево и вправо для арифметических операций. Левый сдвиг на x эквивалентен умножению на 2 ^ x (до тех пор, пока он не переполняется), а правый сдвиг эквивалентен делению на 2 ^ x.

Недавно я видел людей, использующих x < 1 и x → 1 для удвоения и сокращения пополам, хотя я не уверен, что они просто стараются быть умными или действительно есть отличное преимущество над нормальными операторами.

Ответ 7

В этом примере будут показаны операции для всех четырех двухбитовых значений:

10 | 12

1010 #decimal 10
1100 #decimal 12

1110 #result = 14

10 & 12

1010 #decimal 10
1100 #decimal 12

1000 #result = 8

Вот пример использования:

x = raw_input('Enter a number:')
print 'x is %s.' % ('even', 'odd')[x&1]

Ответ 8

Я думаю, что вторая часть вопроса:

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

Рассматривается только частично. Это мои два цента по этому вопросу.

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

Во всех приложениях, которые должны отправлять данные между двумя узлами, например:

  • компьютерные сети;

  • телекоммуникационные приложения (сотовые телефоны, спутниковая связь и т.д.).

В слое связи нижнего уровня данные обычно отправляются в так называемые фреймы. Фреймы - это просто строки байтов, которые отправляются через физический канал. Эти кадры обычно содержат фактические данные плюс некоторые другие поля (закодированные в байтах), которые являются частью того, что называется заголовком . Заголовок обычно содержит байты, которые кодируют некоторую информацию, связанную с состоянием связи (например, с флагами (битами)), счетчики кадров, коды коррекции и обнаружения ошибок и т.д. Чтобы получить переданные данные в кадре и построить кадры для отправки данных, вам понадобятся пористые операции.

В общем, при работе с такими приложениями API доступен, поэтому вам не нужно разбираться со всеми этими деталями. Например, все современные языки программирования предоставляют библиотеки для соединений сокетов, поэтому на самом деле вам не нужно создавать кадры связи TCP/IP. Но подумайте о хороших людях, которые запрограммировали эти API для вас, им наверняка пришлось иметь дело с рамочной конструкцией; используя все виды побитовых операций, чтобы идти назад и вперед от низкоуровневой связи до более высокого уровня.

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

Другое очень различное семейство приложений низкого уровня - это когда вам нужно управлять аппаратным обеспечением с помощью некоторых (древних) портов, таких как параллельные и последовательные порты. Эти порты управляются путем установки некоторых байтов, и каждый бит этих байтов имеет определенное значение с точки зрения инструкций для этого порта (см., Например, http://en.wikipedia.org/wiki/Parallel_port). Если вы хотите создать программное обеспечение, которое что-то делает с этим оборудованием, вам понадобятся побитовые операции для перевода инструкций, которые вы хотите выполнить, в байты, которые порт понимает.

Например, если у вас есть некоторые физические кнопки, подключенные к параллельному порту для управления другим устройством, это строка кода, которую вы можете найти в мягком приложении:

read = ((read ^ 0x80) >> 4) & 0x0f; 

Надеюсь, что это поможет.

Ответ 9

Другим распространенным случаем использования является обработка/проверка прав доступа к файлам. См. Модуль stat Python: http://docs.python.org/library/stat.html.

Например, чтобы сравнить разрешения файлов с нужным набором разрешений, вы можете сделать что-то вроде:

import os
import stat

#Get the actual mode of a file
mode = os.stat('file.txt').st_mode

#File should be a regular file, readable and writable by its owner
#Each permission value has a single 'on' bit.  Use bitwise or to combine 
#them.
desired_mode = stat.S_IFREG|stat.S_IRUSR|stat.S_IWUSR

#check for exact match:
mode == desired_mode
#check for at least one bit matching:
bool(mode & desired_mode)
#check for at least one bit 'on' in one, and not in the other:
bool(mode ^ desired_mode)
#check that all bits from desired_mode are set in mode, but I don't care about 
# other bits.
not bool((mode^desired_mode)&desired_mode)

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

Ответ 10

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

Хорошим и довольно простым примером этого является общее решение игры Nim. Взгляните на Python код на странице Википедии. Он сильно использует побитовое исключение или ^.

Ответ 11

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

import numpy as np
a=np.array([1.2, 2.3, 3.4])
np.where((a>2) and (a<3))      
#Result: Value Error
np.where((a>2) & (a<3))
#Result: (array([1]),)

Ответ 12

Я не видел, чтобы это упоминалось. В этом примере вы покажете вам (-) десятичную операцию для двух битовых значений: A-B (только если A содержит B)

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

111 #decimal 7
-
100 #decimal 4
--------------
011 #decimal 3

с python: 7 и ~ 4= 3 (удалить из 7 битов, которые представляют 4)

001 #decimal 1
-
100 #decimal 4
--------------
001 #decimal 1

с python: 1 и ~ 4= 1 (удалить из 1 битов, которые представляют 4 - в этом случае 1 не содержит "4)..

Ответ 13

Хотя манипуляция битами целого числа полезна, часто для сетевых протоколов, которые могут быть указаны до бита, может потребоваться манипуляция более длинными байтовыми последовательностями (которые нелегко преобразовать в одно целое). В этом случае полезно использовать библиотеку bitstring, которая позволяет выполнять побитовые операции с данными. можно импортировать строку "ABCDEFGHIJKLMNOPQ" в виде строки или в виде шестнадцатеричного и битового сдвига (или выполнять другие побитовые операции):

>>> import bitstring
>>> bitstring.BitArray(bytes='ABCDEFGHIJKLMNOPQ') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
>>> bitstring.BitArray(hex='0x4142434445464748494a4b4c4d4e4f5051') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')

Ответ 14

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