Случай использования в реальном мире побитовых операторов

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

  • И
  • XOR
  • НЕ
  • ИЛИ

Ответ 1

  • Бит-поля (флаги)
    Они являются наиболее эффективным способом представления того, чье состояние определяется несколькими свойствами "да" или "нет". ACL - хороший пример; если вы допустили 4 дискретных разрешения (чтение, запись, выполнение, изменение политики), лучше хранить это в 1 байте, а не в отходах 4. Они могут быть сопоставлены типам перечислений на многих языках для дополнительного удобства.

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

  • Сжатие, шифрование
    Оба они сильно зависят от побитовых алгоритмов. Посмотрите на алгоритм deflate для примера - все в битах, а не в байтах.

  • Конечные машины
    Я говорю прежде всего о том, что встраивается в какое-то оборудование, хотя их можно найти и в программном обеспечении. Они являются комбинаторными по своей природе - они могут буквально "скомпилироваться" до кучи логических ворот, поэтому их нужно выражать как AND, OR, NOT и т.д.

  • Графика Здесь почти нет места, чтобы попасть в каждую область, где эти операторы используются в графическом программировании. XOR (или ^) особенно интересен здесь, потому что повторное применение второго входа отменяет первый. Старые графические интерфейсы использовали этот подход для выделения выделения и других наложений, чтобы исключить необходимость дорогостоящего перерисовки. Они по-прежнему полезны в медленных графических протоколах (т.е. Удаленный рабочий стол).

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

Ответ 2

Это странно?

(value & 0x1) > 0

Он делится на две (четные)?

(value & 0x1) == 0

Ответ 3

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

volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t          value;
uint32_t          set_bit   = 0x00010000;
uint32_t          clear_bit = 0x00001000;

value = *register;            // get current value from the register
value = value & ~clear_bit;   // clear a bit
value = value | set_bit;      // set a bit
*register = value;            // write it back to the register

Кроме того, htonl() и htons() реализованы с использованием операторов & и | (на машинах, endianness (Порядок байтов) не соответствует порядку сети):

#define htons(a) ((((a) & 0xff00) >> 8) | \
                  (((a) & 0x00ff) << 8))

#define htonl(a) ((((a) & 0xff000000) >> 24) | \
                  (((a) & 0x00ff0000) >>  8) | \
                  (((a) & 0x0000ff00) <<  8) | \
                  (((a) & 0x000000ff) << 24))

Ответ 4

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

Ответ 5

Вот некоторые общие идиомы, касающиеся флагов, хранящихся как отдельные биты.

enum CDRIndicators {
  Local = 1 << 0,
  External = 1 << 1,
  CallerIDMissing = 1 << 2,
  Chargeable = 1 << 3
};

unsigned int flags = 0;

Установите флаг Chargeable:

flags |= Chargeable;

Удалить флаг CallerIDMissing:

flags &= ~CallerIDMissing;

Проверьте, установлены ли CallerIDMissing и Chargeable:

if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {

}

Ответ 6

Я использовал побитовые операции при реализации модели безопасности для CMS. У него были страницы, к которым пользователи могли получить доступ, если они были в соответствующих группах. Пользователь может быть в нескольких группах, поэтому нам нужно проверить, было ли пересечение между группами пользователей и группами страниц. Поэтому мы назначили каждой группе уникальный идентификатор power-of-2, например:

Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100

Мы ИЛИ эти значения вместе и сохраняем значение (как один int) со страницей. Например. если к странице можно получить доступ к группам A и B, мы сохраняем значение 3 (которое в двоичном формате равно 00000011) в качестве контроля доступа к страницам. Точно так же мы сохраняем значение идентификаторов группы ORed с пользователем, чтобы представлять, в каких группах они находятся.

Таким образом, чтобы проверить, может ли данный пользователь получить доступ к данной странице, вам просто нужно СО И значения вместе и проверить, не имеет ли значение ненулевое значение. Это очень быстро, так как эта проверка реализована в одной команде, без циклов, без дублирования базы данных.

Ответ 7

Когда у меня есть куча логических флагов, мне нравится хранить их все в int.

Я получаю их, используя побитовое-И. Например:

int flags;
if (flags & 0x10) {
  // Turn this feature on.
}

if (flags & 0x08) {
  // Turn a second feature on.
}

и др.

Ответ 8

Шифрование - это все побитовые операции.

Ответ 9

Я просто использовал bitwise-XOR (^) около трех минут назад для вычисления контрольной суммы для последовательной связи с ПЛК...

Ответ 10

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

int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;

Ответ 11

& = И:
Выделите определенные биты. Вы определяете конкретные биты, которые должны отображаться или не отображается. 0x0 и x очищают все биты в байте, а 0xFF не изменят x. 0x0F отображает бит в нижнем полубайте.

Конверсия:
Чтобы преобразовать более короткие переменные в более длинные с идентификатором бита, необходимо отрегулировать биты, потому что -1 в int равен 0xFFFFFFFF, тогда как -1 в длинном 0xFFFFFFFFFFFFFFFF. Сохранять личность, которую вы применяете для маски после преобразования.

| = OR
Установите биты. Биты будут установлены независимо, если они уже установлены. Многие datastructures (битовые поля) имеют флаги, такие как IS_HSET = 0, IS_VSET = 1, которые могут быть установлены отдельно. Чтобы установить флаги, вы применяете IS_HSET | IS_VSET (в C и сборке это очень удобно читать)

^ = XOR
Найдите биты, которые являются одинаковыми или разными.

~ = НЕ
Флип-бит.

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

Некоторые замечательные хаки:

http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html

Ответ 12

Побитовое и используется для маскировки/извлечения определенной части байта.

1 Байт-переменная

 01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
 --------
 00000010

В частности, для расчетов часто используется оператор сдвига (< < → ).

Ответ 13

Это пример чтения цветов из растрового изображения в байтовом формате

byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */

//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */

//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF;  /* This now returns a red colour between 0x00 and 0xFF.

Я надеюсь, что это крошечные примеры помогут...

Ответ 14

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

Это, конечно, всего лишь один из бесчисленных примеров.

Ответ 15

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

//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
    FileAttributes attributes = File.GetAttributes(targetName);

    if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
        File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));

    File.Delete(targetName);
}

Что касается пользовательских реализаций, здесь приведен пример: Я создал "центр сообщений" для отправки защищенных сообщений от одной установки нашего распределенного приложения к другому. В принципе, он аналогичен электронной почте, в комплекте с Inbox, Outbox, Sent и т.д., Но также имеет гарантированную доставку с чтением квитанций, поэтому есть дополнительные подпапки за пределами "входящих" и "отправленных". Для меня это требовало, чтобы я определял в общем, что такое "в папке" Входящие "или что" в папке отправлено ". Из отправленной папки мне нужно знать, что читать и что непрочитанное. Из того, что непрочитанное, мне нужно знать, что получено и что не получено. Я использую эту информацию для создания предложения dynamic where, которое фильтрует локальный источник данных и отображает соответствующую информацию.

Здесь, как перечисляется объединение:

    public enum MemoView :int
    {
        InboundMemos = 1,                   //     0000 0001
        InboundMemosForMyOrders = 3,        //     0000 0011
        SentMemosAll = 16,                  //     0001 0000
        SentMemosNotReceived = 48,          //     0011
        SentMemosReceivedNotRead = 80,      //     0101
        SentMemosRead = 144,                //     1001
        Outbox = 272,                       //0001 0001 0000
        OutBoxErrors = 784                  //0011 0001 0000
    }

Вы видите, что это делает? По указанию (&) с значением перечисления "Входящие" InboundMemos я знаю, что InboundMemosForMyOrders находится в папке "Входящие".

Здесь приведенная версия метода, который создает и возвращает фильтр, который определяет представление для текущей выбранной папки:

    private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
    {
        string filter = string.Empty;
        if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
        {
            filter = "<inbox filter conditions>";

            if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
            {
                filter += "<my memo filter conditions>";
            }
        }
        else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
        {
            //all sent items have originating system = to local
            filter = "<memos leaving current system>";

            if((view & MemoView.Outbox) == MemoView.Outbox)
            {
                ...
            }
            else
            {
                //sent sub folders
                filter += "<all sent items>";

                if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
                {
                    if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
                    {
                        filter += "<not received and not read conditions>";
                    }
                    else
                        filter += "<received and not read conditions>";
                }
            }
        }

        return filter;
    }

Чрезвычайно простая, но аккуратная реализация на уровне абстракции, которая обычно не требует побитовых операций.

Ответ 16

Я удивлен, что никто не выбрал очевидный ответ на интернет-возраст. Вычисление допустимых сетевых адресов для подсети.

http://www.topwebhosts.org/tools/netmask.php

Ответ 17

Никто, кажется, не упомянул математику с фиксированной точкой.

(Да, я стар, хорошо?)

Ответ 18

Если вы хотите изменить некоторые биты выходов микроконтроллера, но регистр для записи в это байт, вы делаете что-то вроде этого (псевдокод):

char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs

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

Ответ 19

он также может быть полезен в реляционной модели sql, скажем, у вас есть следующие таблицы: BlogEntry, BlogCategory

traditonally вы можете создать связь n-n между ними, используя таблицу BlogEntryCategory или, если записей в BlogCategory не так много, вы можете использовать одно значение в BlogEntry для ссылки на несколько записей в BlogCategory так же, как и с флаговыми перечислениями, в большинстве СУБД есть также очень быстрые операторы для выбора в столбце "помечены"...

Ответ 20

Является ли число x мощностью 2? (Полезно, например, в алгоритмах, где счетчик увеличивается, а действие должно выполняться только логарифмическим числом раз)

(x & (x - 1)) == 0

Каков максимальный бит целого числа x? (Это, например, можно использовать для поиска минимальной мощности 2, которая больше, чем x)

x |= (x >>  1);
x |= (x >>  2);
x |= (x >>  4);
x |= (x >>  8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift

Каков самый младший бит 1 целого числа x? (Помогает найти количество раз, делящееся на 2.)

x & -x

Ответ 21

Побитовые операторы полезны для циклических массивов, длина которых равна 2. Как упоминалось многими людьми, побитовые операторы чрезвычайно полезны и используются в Флагах, Графика, Сеть, Шифрование. Не только это, но и очень быстро. Мое личное любимое использование - это цикл массива без условностей. Предположим, у вас есть массив с нулевым индексом (например, индекс первого элемента равен 0), и вам нужно зацикливать его на неопределенный срок. Неоднократно я имею в виду переход от первого элемента к последнему и возвращение к первому. Один из способов реализовать это:

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    if (i >= arr.length) 
        i = 0;
}

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

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    i = i % arr.length;
}

Нижняя сторона этих двух методов заключается в том, что оператор модуля стоит дорого, так как он ищет остаток после целочисленного деления. И первый метод запускает оператор if на каждой итерации. Однако с побитовым оператором, если длина вашего массива равна 2, вы можете легко создать последовательность, подобную 0 .. length - 1, используя & (побитовый и) оператор, например i & length. Поэтому, зная это, код сверху становится

int[] arr = new int[8];
int i = 0;
while (true){
    print(arr[i]);
    i = i + 1;
    i = i & (arr.length - 1);
}

Вот как это работает. В двоичном формате каждое число, которое является степенью 2, вычитаемой на 1, выражается только с единицами. Например, 3 в двоичном формате 11, 7 - 111, 15 - 1111 и т.д., Вы получаете идею. Теперь, что произойдет, если вы & любое число против числа, состоящего только из двоичных? Скажем, мы это делаем:

num & 7;

Если num меньше или равно 7, результат будет num, потому что каждый бит & -ed с 1 сам по себе. Если num больше 7, на компьютере & компьютер рассмотрит 7 ведущих нулей, которые, конечно, останутся нулями после операции &, останется только конечная часть. Как и в случае 9 & 7 в двоичном формате, это будет выглядеть как

1001 & 0111

результат будет равен 0001, который равен 1 в десятичном значении и адресует второй элемент в массиве.

Ответ 22

Обычно побитовые операции выполняются быстрее, чем умножение/деление. Поэтому, если вам нужно умножить переменную x на 9, вы сделаете x<<3 + x, которая будет на несколько циклов быстрее, чем x*9. Если этот код находится внутри ISR, вы сэкономите время отклика.

Аналогичным образом, если вы хотите использовать массив как круговую очередь, было бы быстрее (и более элегантно) обрабатывать проверки вокруг с помощью бит-мутных операций. (размер вашего массива должен быть 2). Например: вы можете использовать tail = ((tail & MASK) + 1) вместо tail = ((tail +1) < size) ? tail+1 : 0, если вы хотите вставить/удалить.

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

Также n-разрядная растровая карта может быть действительно крутой и компактной структурой данных. Если вы хотите выделить пул ресурсов размером n, мы можем использовать n-биты для представления текущего состояния.

Ответ 23

Я использую их для нескольких опций выбора, таким образом я сохраняю только одно значение вместо 10 или более

Ответ 24

Я видел, как они использовались в системах контроля доступа на основе ролей.

Ответ 25

Всякий раз, когда я впервые начинал программирование на С, я понял таблицы истинности и все такое, но не все нажимали на то, как на самом деле использовать его, пока не прочитаю эту статью http://www.gamedev.net/reference/articles/article1563.asp (который дает реальные примеры жизни)

Ответ 26

В моем вопросе есть реальное использование мира -
Отвечать только на первое уведомление WM_KEYDOWN?

При использовании сообщения WM_KEYDOWN в Windows C api бит 30 задает предыдущее состояние ключа. Значение равно 1, если клавиша не указана до отправки сообщения или равна нулю, если клавиша поднята

Ответ 27

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

Кодировка символов:

if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {

Структуры данных:

ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;

Драйверы базы данных:

dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);

Реализация компилятора:

opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;

Ответ 28

Я не думаю, что это считается поразрядным, но Ruby Array определяет заданные операции через нормальные целочисленные побитовые операторы. Итак [1,2,4] & [1,2,3] # => [1,2]. Аналогично для a ^ b #=> set difference и a | b #=> union.

Ответ 29

Если вы когда-либо захотите рассчитать свой mod mod (%) определенную мощность 2, вы можете использовать yourNumber & 2^N-1, который в этом случае будет таким же, как yourNumber % 2^N.

number % 16 = number & 15;
number % 128 = number & 127;

Это, вероятно, полезно только в качестве альтернативы работе модуля с очень большим дивидендом, равным 2 ^ N... Но даже тогда его ускорение скорости по сравнению с работой модуля незначительно в моем тесте на .NET 2.0. Я подозреваю, что современные компиляторы уже выполняют такие оптимизации. Кто-нибудь знает об этом больше?

Ответ 30

Линейное решение Tower Of Hanoi использует побитовые операции для решения проблемы.

public static void linear(char start, char temp, char end, int discs)
{
    int from,to;
    for (int i = 1; i < (1 << discs); i++) {
        from = (i & i-1) % 3;
        to = ((i | i-1) + 1) % 3;
        System.out.println(from+" => "+to);
    }
}

Объяснение этого решения можно найти здесь