我希望以快速有效的方式为 Morton Z-Order Encoding 和 Decoding 在 C 中编写两个函数,即。
uint64_t morton_encode(uint32_t xindex, uint32_t yindex, uint32_t zindex);
void morton_decode(uint64_t morton_number, uint32_t *xindex, uint32_t *yindex, uint32_t *zindex);
我之前已经关注了这些问题
我目前基于 SO 和开源代码的解决方案是
uint64_t spread(uint64_t w) {
w &= 0x00000000001fffff;
w = (w | w << 32) & 0x001f00000000ffff;
w = (w | w << 16) & 0x001f0000ff0000ff;
w = (w | w << 8) & 0x010f00f00f00f00f;
w = (w | w << 4) & 0x10c30c30c30c30c3;
w = (w | w << 2) & 0x1249249249249249;
return w;
}
uint64_t morton_encode(uint32_t x, uint32_t y, uint32_t z) {
return ((spread((uint64_t)x)) | (spread((uint64_t)y) << 1) | (spread((uint64_t)z) << 2));
}
///////////////// For Decoding //////////////////////
uint32_t compact(uint64_t w) {
w &= 0x1249249249249249;
w = (w ^ (w >> 2)) & 0x30c30c30c30c30c3;
w = (w ^ (w >> 4)) & 0xf00f00f00f00f00f;
w = (w ^ (w >> 8)) & 0x00ff0000ff0000ff;
w = (w ^ (w >> 16)) & 0x00ff00000000ffff;
w = (w ^ (w >> 32)) & 0x00000000001fffff;
return (uint32_t)w;
}
void morton_decode(uint64_t morton_number, uint32_t *xindex, uint32_t *yindex, uint32_t *zindex){
*xindex = compact(code);
*yindex = compact(code >> 1);
*zindex = compact(code >> 2);
}
我最近遇到了这个 SO 问题(在尝试使用 2D morton 代码时):2d morton code encode decode 64bits
#include <immintrin.h>
#include <stdint.h>
// on GCC, compile with option -mbmi2, requires Haswell or better.
uint64_t xy_to_morton (uint32_t x, uint32_t y)
{
return _pdep_u32(x, 0x55555555) | _pdep_u32(y,0xaaaaaaaa);
}
uint64_t morton_to_xy (uint64_t m, uint32_t *x, uint32_t *y)
{
*x = _pext_u64(m, 0x5555555555555555);
*y = _pext_u64(m, 0xaaaaaaaaaaaaaaaa);
}
据我了解,这不是一个可移植的解决方案,但由于我(将)运行我的代码的每个系统都有 Haswell CPU(甚至在 HPC 集群上)。我的问题:
- 如何为 3D 系统修改此代码或这些 BMI 指令集是否可用于编码解码 3D 莫顿数?
- 考虑到我需要在每个时间步解码几百万个莫顿数字并且有数百万个这样的时间步长,使用这些指令是否比我现在使用的标准解决方案更有效。
编辑:对于第一季度,我非常接近解决方案,但仍然无法弄清楚
0x55555555 -> 0000 0000 0101 0101 0101 0101 0101 0101 0101 0101
0xaaaaaaaa -> 0000 0000 1010 1010 1010 1010 1010 1010 1010 1010
很明显,掩码是交替的 x 和 y 位。所以对于 3d 我需要得到一个像
0000 0000 01 001 001 001 001 001 001 001 001 001 001 (for x)
0000 0000 01 010 010 010 010 010 010 010 010 010 010 (for y)
0000 0000 01 100 100 100 100 100 100 100 100 100 100 (for z)
^
我对 64 位 morton 代码的 ^ 标记之前的位有点困惑,只有 x、y 和 z 的前 21 位是 32 位整数应该很重要。