Этот вопрос: Как удалить чередование битов (UnMortonizing?) имеет хороший ответ для извлечения одной из двух половинок числа Morton (только нечетные биты), но мне нужно решение, которое извлекает обе части (нечетные биты и четные биты) как можно меньше операций.
Для моего использования мне нужно будет взять 32-битный int и извлечь два 16-битных ints, где один - четные биты, а другой - нечетные биты, сдвинутые вправо на 1 бит, например.
input, z: 11101101 01010111 11011011 01101110
output, x: 11100001 10110111 // odd bits shifted right by 1
y: 10111111 11011010 // even bits
Кажется, что существует множество решений, использующих сдвиги и маски с магическими числами для генерации чисел Мортона (то есть чередующихся битов), например. Перемешать биты по двоичным магическим номерам, но я еще ничего не нашел для выполнения обратного (то есть деперемежения).
UPDATE
После повторного чтения раздела из Hacker Delight о совершенных перетасовках/беспорядках я нашел несколько полезных примеров, которые я адаптировал следующим образом:
// morton1 - extract even bits
uint32_t morton1(uint32_t x)
{
x = x & 0x55555555;
x = (x | (x >> 1)) & 0x33333333;
x = (x | (x >> 2)) & 0x0F0F0F0F;
x = (x | (x >> 4)) & 0x00FF00FF;
x = (x | (x >> 8)) & 0x0000FFFF;
return x;
}
// morton2 - extract odd and even bits
void morton2(uint32_t *x, uint32_t *y, uint32_t z)
{
*x = morton1(z);
*y = morton1(z >> 1);
}
Я думаю, что это все еще можно улучшить, как в его текущей скалярной форме, так и в использовании SIMD, поэтому меня все еще интересуют лучшие решения (скалярные или SIMD).