1. 程式人生 > >djb2:一個產生簡單的隨機分佈的雜湊函式

djb2:一個產生簡單的隨機分佈的雜湊函式

目錄

LCG演算法

djb2與LCG很類似,故先介紹 LCG。

LCG(linear congruential generator)演算法是一個古老的產生隨機數的演算法。由以下引數產生

引數 m a c X
性質 模數 乘數 加數 隨機數
作用 取模 移位 偏移 作為結果

LCG演算法是如下的一個遞推公式,每下一個隨機數是當前隨機數向左移動 log2 a 位,加上一個 c,最後對 m 取餘,使隨機數限制在 0 ~ m-1 內

從該式可以看出,該演算法由於構成簡單,具有以下優點:

  • 計算速度快
  • 易於實現
  • 易於寫入硬體

以下是針對不同引數 lcg 產生隨機數的效果圖

可以看出,針對不同的引數,lcg產生的效果差別很大

以下是針對不同環境下的引數選擇

詳見wiki

示例程式碼

def lcg(modulus, a, c, seed):
    while True:
        seed = (a * seed + c) % modulus
        yield seed

djb2

djb2是一個產生隨機分佈的的雜湊函式,與LCG的演算法相似。

以下是 djb2 的雜湊函式:

X = (a * X) + c; // "mod M", M = 2^32 或 2^64

示例程式碼


// generates a hash value for a sting
// same as djb2 hash function
//構造雜湊函式 f(hash)= hash * 33 + c
unsigned int CountMinSketch::hashstr(const char *str) {
  unsigned long hash = 5381;
  int c;
  while (c = *str++) {
    hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  }
  return hash;
}

本部分利用djb2處理字串。
其中引數常有以下取值:
M=2^32

M常取一個較大的質數,以減少衝突。

由於雜湊函式構造簡單,使用移位和相加的操作,所以計算速度快。

要注意hash值的計算,在不同機器上,可能會造成溢位的問題,可以及時對hash值取餘。但是會增加計算開銷,造成hash範圍減小的問題。

為什麼選擇引數33和

33 was chosen because:

1) 乘法易於移位或相加

2) 從移位和加法實現中可以看到,使用33可以複製雜湊累加器中的大多數輸入位,然後將這些位相對地分散開來。這有助於形成好的雪崩現象。使用較大的移位將複製更少的位,使用較小的移位將使位互動更區域性,並使互動擴充套件所需的時間更長。

3) 32 = 2^5,32 與移 5 位相關,有助於將每一個字串的每一位位元都作用到最終的雜湊值當中

4) 在考慮ASCII字元資料時,5的移位是一個很好的移位量。ASCII字元可以看作是4位字元型別選擇器和4位字元型別選擇器。前4位的數字都是0x3。因此,8位移位將導致具有特定含義的位與具有相同含義的其他位相互作用。4位或2位的移位同樣會在相似的位之間產生強烈的互動作用。5位的移位使得一個字元的4個低階位中的許多位與同一字元的4個上位中的許多強相互作用。

5381 was chosen because

1) 選擇5381並不太重要,很多其他的大的質數數也可以執行地很好。

雜湊選擇參考

源自 https://stackoverflow.com/questions/1579721/why-are-5381-and-33-so-important-in-the-djb2-algorithm

djb2不是一個快速雜湊函式,因為它每次處理輸入一個字元,並且不嘗試使用指令級並行。

在現代處理器,乘法時該演算法要快得多了乘法和其他因素(如2 ^ 13 + 2 ^ 5 + 1)可能也有類似的表現,有更好的輸出,更容易寫。

一個好的非加密雜湊函式不希望產生隨機輸出。相反,給定兩個幾乎完全相同的輸入,它希望產生完全不同的輸出。

如果你的輸入值是隨機分佈的,你不需要一個好的雜湊函式,你可以使用你輸入的任意一組位元。一些現代雜湊函式(Jenkins 3, Murmur, probably CityHash)產生的輸出分佈比高度相似的隨機輸入更好。

選擇雜湊函式的詳細部落格 https://blog.csdn.net/xu20082100226/article/details/52651212