这个问题: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;
...

10-06 05:06