djb2:一個產生簡單的隨機分佈的雜湊函式
目錄
LCG演算法
djb2與LCG很類似,故先介紹 LCG。
LCG(linear congruential generator)演算法是一個古老的產生隨機數的演算法。由以下引數產生
引數 | m | a | c | X |
---|---|---|---|---|
性質 | 模數 | 乘數 | 加數 | 隨機數 |
作用 | 取模 | 移位 | 偏移 | 作為結果 |
LCG演算法是如下的一個遞推公式,每下一個隨機數是當前隨機數向左移動 log2 a 位,加上一個 c,最後對 m 取餘,使隨機數限制在 0 ~ m-1 內
從該式可以看出,該演算法由於構成簡單,具有以下優點:
- 計算速度快
- 易於實現
- 易於寫入硬體
以下是針對不同引數 lcg 產生隨機數的效果圖
可以看出,針對不同的引數,lcg產生的效果差別很大
以下是針對不同環境下的引數選擇
示例程式碼
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