这个问题:How to de-interleave bits (UnMortonizing?)对于提取莫顿数的两半之一(仅是奇数位)有一个很好的答案,但是我需要一种解决方案,以尽可能少的操作提取两个部分(奇数位和偶数位) 。
对于我的用途,我需要获取32位int并提取两个16位int,其中一个是偶数位,另一个是奇数位右移1位,例如
input, z: 11101101 01010111 11011011 01101110
output, x: 11100001 10110111 // odd bits shifted right by 1
y: 10111111 11011010 // even bits
似乎有很多使用移位和带有魔术数字的掩码来生成莫顿数(即交织位)的解决方案,例如Interleave bits by Binary Magic Numbers,但是我还没有找到任何相反的方法(即解交织)。
更新
重新阅读了《 Hacker's 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)感兴趣。
最佳答案
如果您的处理器有效地处理64位整数,则可以合并这些操作...
int64 w = (z &0xAAAAAAAA)<<31 | (z &0x55555555 )
w = (w | (w >> 1)) & 0x3333333333333333;
w = (w | (w >> 2)) & 0x0F0F0F0F0F0F0F0F;
...