Когда выполняются поразрядные операции

Я знаю основную предпосылку какой побитовой операции (хотя бы оценил объяснение "для чайников" ); однако я не знаю, когда целесообразно использовать эту технику.

Я понимаю, что более старые архитектуры процессоров

Ответ 1

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

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

Пример:

A User таблица базы данных с полем tinyint, называемым Permission. Поле заполняется с использованием значения, созданного с перечислением, значения которого равны 2 ^ n.

[Flags]
public enum Permission : byte
{
    None = 0,
    ManageUsers = 1 << 0,
    CreateOrders = 1 << 1,
    PurchaseEquipment = 1 << 2,
    CancelOrders = 1 << 3,
}

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

Пример битстаффинга (Grant ManageUsers и CreateOrders):

Permission userPermissions = Permission.ManageUsers | Permission.CreateOrders;

Проверка разрешения на выбор:

public bool HasPermissions(Permission userPermissions, Permission permissionsToCheckFor)
{
    return permissionsToCheckFor == Permission.None ? 
        false : 
        (userPermissions & permissionsToCheckFor) == permissionsToCheckFor;
}

Ответ 2

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

Концептуально байты, шорты и ints представляют собой очень маленькие массивы бит, а побитовые операторы - логические операторы массива. В С# в настоящее время побитовые операторы в основном используются для перечислений [Flags] и в вычислениях для GetHashCode, но существуют бесконечные способы использования массивов бит.

Ответ 3

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

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

Ответ 4

Они могут быть действительно полезны во встроенных ситуациях управления, когда пространство стоит на высоте. Например, один байт данных может представлять 8 битов ввода-вывода, а маски могут использоваться для извлечения интересующих бит из порта ввода-вывода (например, если PIN0 = 1, PIN1 = 2, PIN2 = 4, PIN3 = 8 и т.д., То:

  • Чтобы получить значение PIN0, мы можем сказать PORT0 & PIN0 == 0.
  • Чтобы установить PIN1 в 1, мы можем cay PORT0 |= PIN1.
  • Чтобы установить PIN2 в 0, можно сказать PORT0 &= ~PIN2.

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

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

Ответ 5

Один из способов, по которым я время от времени использую побитовые операторы, - создавать подмножества заданной строки/массива с использованием двоичной маски, он выглядит следующим образом: (извините, код С++)

string s = "abcde";
for(int i = 0; i < 1<<s.size(); i++) {
  string tmp;
  for(int j = 0; j < s.size(); j++) if(i & 1<<j) tmp.push_back(s[j]);
  cout<<tmp<<endl; 
}

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