如何创建具有64位输出的良好hash_combine(受boost::hash_combine的启发)

How to create a good hash_combine with 64 bit output (inspired by boost::hash_combine)

本文关键字:hash combine boost 何创建 创建 64位 输出      更新时间:2023-10-16

目前Boost有hash_combine函数输出32位无符号整数(准确地说,是size_t)。参考:

http://www.boost.org/doc/libs/1_43_0/doc/html/hash/reference.html boost.hash_combine

http://www.boost.org/doc/libs/1_43_0/doc/html/hash/combine.html

boost::hash_combine中的幻数

我想探索一下如何创建64位版本的hash_combine。

第一件事是得到64位的黄金分割率或其他无理数。

第二部分是使用移位。这部分相当棘手,我想问是否有最佳实践或指南使用移位来获取哈希值?或者像原始代码那样选择移位:

seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 

是完全随机的?

还有如何评估hash_combine的输出以确保它不会比原始哈希函数hash_value产生更多的碰撞?

如果您只想要一个将2个64位值散列为一个的hash_combine,并且您不需要一个新的字符串散列函数,您可以从CityHash中提取一小段代码,类似于这样(假设size_t是64位无符号整数,添加您喜欢的预处理器或模板技巧来验证它):

template <class T> inline void hash_combine(std::size_t& seed, const T& v)
{
    std::hash<T> hasher;
    const std::size_t kMul = 0x9ddfea08eb382d69ULL;
    std::size_t a = (hasher(v) ^ seed) * kMul;
    a ^= (a >> 47);
    std::size_t b = (seed ^ a) * kMul;
    b ^= (b >> 47);
    seed = b * kMul;
}

(我认为在这里和其他地方复制这个片段是可以的,因为它不构成CityHash代码的"实质性部分",但请检查CityHash源代码&许可协议自行决定)

请阅读http://burtleburtle.net/bob/hash/doobs.html以获得有关散列函数设计的一些基本信息,并阅读http://burtleburtle.net/bob/hash/中的其他文章以获得更详细的信息。CityHash使用http://code.google.com/p/smhasher/进行了测试,您可能可以使用相同的测试套件测试您的hash_combine

虽然我不是哈希方面的专家,但最近的哈希函数的设计使我相信hash_combine()使用的2-shift技术boost不再是最先进的,可以改进。

boost::hash_combine不是完全随机的,它甚至不是很好地分布或特别好。

组合两个散列的一个好方法是首先确保两个散列分布良好,然后可以将两个散列与xor组合。为了确保它们被很好地分布,使用一个好的整数哈希函数。

把它们放在一起,你可能有:

uint64_t xorshift(const uint64_t& n,int i){
  return n^(n>>i);
}
uint64_t hash(const uint64_t& n){
  uint64_t p = 0x5555555555555555; // pattern of alternating 0 and 1
  uint64_t c = 17316035218449499591ull;// random uneven integer constant; 
  return c*xorshift(p*xorshift(n,32),32);
}
uint64_t hash_combine(const uint64_t& seed, const uint64_t& v) {
  uint64_t c = 17316035218449499591ull;// random integer constant;
  return hash(v)^(seed+c);
}

如果散列的分布不足以满足您的目的,只需对值进行双重散列,可能像这样:hash(hash(v))^seed