Мне нужна быстрая и простая хеш-функция, которая создает уникальный идентификатор для пары значений uint32_t
, то есть одно и то же хеш-значение для (2,7)
и (7,2)
.
Есть идеи?
Мне нужна быстрая и простая хеш-функция, которая создает уникальный идентификатор для пары значений uint32_t
, то есть одно и то же хеш-значение для (2,7)
и (7,2)
.
Есть идеи?
Чтобы ответить на мой собственный вопрос, решение:
uint64_t hash(uint32_t x, uint32_t y)
{
const uint64_t a = static_cast<uint64_t>(x);
const uint64_t b = static_cast<uint64_t>(y);
if (x < y) return (b << 32) | a;
else return (a << 32) | b;
}
Который можно улучшить до версии без филиалов.
uint64_t hash(uint32_t x, uint32_t y)
{
const uint64_t a = static_cast<uint64_t>(x);
const uint64_t b = static_cast<uint64_t>(y);
const uint64_t h0 = (b << 32) | a;
const uint64_t h1 = (a << 32) | b;
return (x < y) ? h0 : h1; // conditional move (CMOV) instruction
}
Эти методы являются идеальными хеш-функциями — они гарантируют нулевые коллизии. Однако у них есть недостаток, заключающийся в том, что вы не можете хешировать значения выше 2^32 - 1
.
constexpr uint32_t hash_max = ...;
constexpr uint32_t commutative_hash(uint32_t i, uint32_t j) {
return (i*j + (i*i)*(j*j) + (i*i*i)*(j*j*j)) % hash_max;
};
Дополнительные скобки для компилятора - так будет проще оптимизировать это выражение.
Не используйте никакие условные инструкции (или std::max
/std::min
), которые прерывают конвейер процессора (и работают медленно), если вы хотите сделать быструю функцию.
if (x>y)
, когда у меня была точно такая же потребность, как и у вас, но теперь, когда я думаю об этом,hash(x) ^ hash(y)
подошёл бы также (с той проблемой, что все пары идентичных элементов(x, x)
имеют одинаковый хэш. Это может быть проблемой для некоторые приложения) 28.07.2013max << 32
вызывает неопределенное поведение (поскольку вы выполняете сдвиг на величину ›= размеру типа данных). Только после|
результат гарантированно будет приведен кuint64_t
. На практике ваш компилятор все равно выполняет 64-битные вычисления, но это нельзя предполагать наверняка. 06.03.2017