如何创建具有64位输出的良好hash_combine(受boost::hash_combine的启发)
How to create a good hash_combine with 64 bit output (inspired by boost::hash_combine)
目前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.htmlboost::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
- 什么是"#include <boost/functional/hash.hpp> "?
- 对自定义类使用 std::hash<uint64_t>
- std::hash<std::string> 可以为不同的字符串返回相同的值吗?
- C++std::hash实现总是确定性的吗
- std::hash for std::chrono::duration
- Hash for a std::pair, for use in an unordered_map
- 为什么在这种特殊情况下不需要将 std::hash() 的专用化注入到 std 命名空间中?
- 为什么当我在MD5 Hash中转换相同的C 字符串时,每次都会获得不同的输出
- 在使用 JNI 将 c++ unordered_map转换为 java hashMap之前将其转换为 java hash
- "The C++ Library doesen't provide a hash for this type." - 在 std::unordered_map 中使用自己的类
- Qt/C++ hash of hashes
- 为什么不区分大小写适用于 std::unordered_set的 std::hash 函数?
- 错误:未使用不完整的类型'struct std::hash<>'无效
- 用于unordered_set<BSTR>的 Hash & EqualTo 函数
- 无法专门化 std::hash 以unordered_map存储自定义类型
- 为模板类嵌套类定义 std::hash 时出现编译错误
- Return value of std::hash ofr (x86/x64)
- Xcode C++ MD5 hash
- 明确的专业化;'std::hash<_Kty>' 已被实例化
- STD :: HASH :: operator() - 例外保证