如何用64位输出创建一个好的hash_combine(灵感来自boost :: hash_combine)

时间:2011-12-15 01:11:33

标签: c++ boost hash

目前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

Magic number in boost::hash_combine

我想探讨如何创建64位版本的hash_combine。

第一件事是获得黄金比例或任何其他无理数的64位。

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

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

是完全随意的吗?

另外,如何评估hash_combine的输出以确保它不会产生比原始哈希函数hash_value更多的冲突?

3 个答案:

答案 0 :(得分:3)

如果你只想要一个散列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来源和许可协议以确定自己)

答案 1 :(得分:2)

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

虽然我不是哈希专家,但最近哈希函数的设计让我相信2档技术提升的hash_combine()使用不再是最先进的,可以改进上。

答案 2 :(得分:0)

boost::hash_combine并非完全随机,它甚至分布也不均匀或particularly good

组合两个散列的一种好方法是首先确保两个散列分布均匀,然后可以将两个散列与xor组合。为确保它们分布均匀,请使用good integer hash function

将所有内容放在一起:

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