簡體   English   中英

如何用 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.html

boost::hash_combine 中的幻數

我想探索如何創建 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM