[英]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.html
我想探索如何創建 64 位版本的 hash_combine。
第一件事是在 64 位中獲得黃金比例或任何其他無理數。
第二部分是使用班次。 這部分相當棘手,我想問一下是否有關於使用移位獲取哈希值的最佳實踐或指南? 或者選擇像原始代碼一樣的班次:
seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
是完全隨機的嗎?
還如何評價的輸出hash_combine
,以確保它不會比原來的散列函數創建更多的碰撞hash_value
?
如果您只想要一個 hash_combine 將 2 個 64 位值散列為一個,並且您不需要一個新的字符串散列函數,您可以只從 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
。
雖然我不是散列方面的專家,但最近散列函數的設計讓我相信 boost 的hash_combine()
使用的 2-shift 技術不再是最先進的,可以改進。
boost::hash_combine
不是完全隨機的,它甚至不是很好地分布或特別好。
組合兩個散列的一個好方法是首先確保兩個散列分布良好,然后您可以將兩者與異或組合。 為確保它們分布良好,請使用良好的整數散列函數。
把它們放在一起,你可能有:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.