Я хочу написать две функции для 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);
Я ранее следовал за вопросами
как вычислить число 3-х миньонов с чередованием битов по 3 дюйма
Мое текущее решение на основе 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): 2-й Mort-код кодирует декодировать 64 бит
#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 (даже на кластере 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, только первые 21 бит x, y и z, которые являются 32-битными целыми числами, должны иметь значение.