Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Найдите все 2-битные значения, соответствующие другому двоичному шаблону, а затем просуммируйте их.

Автор вопроса: Max Kanat-AlexanderОтветов: 1

Первое значение:

У меня есть двоичное значение, которое на самом деле представляет собой компактную серию 2-битных значений. (То есть каждые 2 бита в двоичном значении представляют 0, 1, 2 или 3.) Таким образом, например, 0, 3, 1, 2 становится 00110110. В этой двоичной строке меня интересуют только 3 ( или, наоборот, я мог бы перевернуть биты и заботиться только о 0, если это облегчит ваш ответ). Все остальные числа не имеют значения (по причинам, которые мы рассмотрим чуть позже).

Второе значение:

У меня есть второе двоичное значение, которое также представляет собой сжатую серию 2-битных значений, представленных таким же образом. Он имеет ту же длину, что и первое значение.

Математика:

Мне нужна сумма 2-битных чисел во втором значении, которые имеют ту же позицию, что и 3 из первого значения. Другими словами, если у меня есть:

First:  11000011
Second: 01111101

Тогда мой ответ будет "2" (я добавил первое и последнее число из "Второго" вместе, потому что это были единственные, у которых было "11" в первом значении, которое им соответствовало.)

Я хочу сделать это за как можно меньшее количество тактов (либо на графическом процессоре, либо на архитектуре x86). Однако я обычно ищу алгоритм, а не решение на ассемблере. Есть ли способ быстрее, чем маскировать два бита за раз от каждого числа и запускать несколько циклов?

  • Вы имели в виду "3" вместо "4" для 11? Julien Lebosquain 12.05.2012

cc++computer-sciencebit-manipulation

Ответы

Ответ 1 · рейтинг 11 · Antti Huima

Конечно.

 // the two numbers
 unsigned int a;
 unsigned int b;

Теперь создайте маску из a, которая содержит бит "1" в нечетной позиции, только если в a было "11", заканчивающееся в той же позиции.

 unsigned int mask = a & (a >> 1) & 0x55555555;

Разверните его, чтобы вернуть шаблон "11":

 mask = mask | (mask << 1);

Так что теперь, если a был 1101100011, маска 1100000011.

Затем замаскируйте b маской:

 b = b & mask;

Затем вы можете выполнить сложение (замаскированных) чисел из b параллельно:

 b = (b & 0x33333333) + ((b & 0xcccccccc) >> 2);
 b = (b & 0x0f0f0f0f) + ((b & 0xf0f0f0f0) >> 4);
 b = (b & 0x00ff00ff) + ((b & 0xff00ff00) >> 8);
 b = (b & 0x0000ffff) + ((b & 0xffff0000) >> 16);

Для 32-битного числа сумма теперь находится в младших битах b. Это общеизвестный шаблон для параллельного добавления битовых полей. Для более чем 32-битных чисел вы должны добавить еще один раунд для 64-битных чисел и два раунда для 128-битных чисел.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы