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



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



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



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

679   15  

15 ответов:

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

  • 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)
  • The & 15 операция будет убедиться, что оба значения имеют только нижние 4 бита.
  • The << 4 это 4-битный сдвиг влево для перемещения val1 в верхние 4 бита 8-битного значения.
  • The | просто объединяет эти два вместе.

если val1 7 и val2 в 4:

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

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

| используется для установки определенного бита в 1

& используется для проверки или очистки определенного бита

  • установите бит (где n-номер бита, а 0-наименее значимый бит):

    unsigned char a |= (1 << n);

  • очистить немного:

    unsigned char b &= ~(1 << n);

  • переключить a бит:

    unsigned char c ^= (1 << n);

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

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

например, вот такой 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)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

надеюсь, что это помогает.

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

x | 2

0001 //x
0010 //2

0011 //result = 3

x & 1

0001 //x
0001 //1

0001 //result = 1

думаю 0 как false и 1 как true. Затем побитовые и (&) и или (|) работают так же, как обычные и и или за исключением того, что они делают все биты в значении сразу. Как правило, вы увидите, что они используются для флагов, если у вас есть 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 для удвоения и деления пополам, хотя я не уверен, что они просто пытаются быть умными или если действительно есть явное преимущество над нормальным операторы.

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

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]

Другой распространенный вариант использования-это управление / тестирование прав доступа к файлам. Смотрите Модуль статистики 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() для каждого из них.

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

хорошим и довольно простым примером этого является общее решение игры Nim. Взгляните на Python код страница Википедии. Это делает интенсивное использование побитового эксклюзивный или,^.

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

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]),)

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

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

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

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

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

С питон: 1 & ~4 = 1 (Удалите из 1 биты, представляющие 4-в этом случае 1 не 'содержит' 4)..

наборы

наборы могут быть объединены с помощью математических операций.

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

Попробуйте Сами:

first = {1, 2, 3, 4, 5, 6}
second = {4, 5, 6, 7, 8, 9}

print(first | second)

print(first & second)

print(first - second)

print(second - first)

print(first ^ second)

результат:

{1, 2, 3, 4, 5, 6, 7, 8, 9}

{4, 5, 6}

{1, 2, 3}

{8, 9, 7}

{1, 2, 3, 7, 8, 9}

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

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

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

Comments

    Ничего не найдено.