Как удалить чередование битов (UnMortonizing?) - PullRequest
23 голосов
/ 29 июня 2010

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

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

EDIT:

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

Ответы [ 3 ]

33 голосов
/ 13 июля 2010

Учитывая, что в вашем приложении каждый второй бит равен 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 голосов
/ 29 июня 2010

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

0 голосов
/ 30 июня 2010

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

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

, которое бы вытянуло все нечетные биты из a и поместило бы их в b.

...