Как деинтегрировать биты (UnMortonizing?)

Каков наиболее эффективный способ деинтерлейции битов из 32-битного int? В этом конкретном случае меня беспокоят только нечетные биты, хотя я уверен, что просто обобщать любое решение для обоих наборов.

Например, я хочу преобразовать 0b01000101 в 0b1011. Какой самый быстрый способ?

EDIT:

В этом приложении я могу гарантировать, что четные биты - все нули. Могу ли я воспользоваться этим фактом, чтобы улучшить скорость или уменьшить пространство?

Ответ 1

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

x = (x | (x >> 1)) & 0x33333333;
x = (x | (x >> 2)) & 0x0f0f0f0f;
x = (x | (x >> 4)) & 0x00ff00ff;
x = (x | (x >> 8)) & 0x0000ffff;

Первый шаг выглядит следующим образом:

  0a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p   x
| 00a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0   x >> 1
  --------------------------------
= 0aabbccddeeffgghhiijjkkllmmnnoop   x | (x >> 1)
& 00110011001100110011001100110011   0x33333333
  --------------------------------
= 00ab00cd00ef00gh00ij00kl00mn00op   (x | (x >> 1)) & 0x33333333

Затем второй шаг работает с двумя битами за раз и т.д.

Ответ 2

С точки зрения скорости, таблица поиска 16 бит шириной с 2 ​​^ 32 входами будет трудно превзойти! Но если у вас не так много памяти, четыре поиска в таблице с 256 входами, плюс несколько сдвигов и AND, чтобы сшить их вместе, может быть лучшим выбором. Или, может быть, сладкое пятно находится где-то посередине... это зависит от имеющихся у вас ресурсов и как стоимость инициализации таблицы поиска будет амортизирована по количеству запросов, которые необходимо выполнить.

Ответ 3

Я не уверен, как бы быстро это было, но вы могли бы сделать что-то вроде

int a = 0b01000101;
int b = 0;
int i = 0;
while (a > 0) {
    b |= (a & 1) << i;
    a >>= 2;
}

Что бы вытащить все нечетные биты из a и поместить их на b.