time33 雜湊函數,又叫 DJBX33A,Bernstein’s hash

來源:互聯網
上載者:User

php, apache, perl, bsddb都使用time33雜湊.

<br />inline unsigned time33(char const*str, int len)<br />{<br /> unsigned long hash = 5381;<br /> /* variant with the hash unrolled eight times */<br /> for (; len >= 8; len -= 8) {<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> hash = ((hash << 5) + hash) + *str++;<br /> }<br /> switch (len) {<br /> case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */<br /> case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */<br /> case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */<br /> case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */<br /> case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */<br /> case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */<br /> case 1: hash = ((hash << 5) + hash) + *str++; break;<br /> case 0: break;<br /> }<br /> return hash;<br />}  
最簡單的版本

   uint32_t time33(char const *str, int len)<br /> {<br /> unsigned long hash = 0;<br /> for (int i = 0; i < len; i++) {<br /> hash = hash *33 + (unsigned long) str[i];<br /> }<br /> return hash;<br /> }
這個版本最可以體現time33的演算法思路,夠簡單。

把乘法操作換成位操作
   unsigned long time33(char const *str, int len)<br /> {<br /> unsigned long hash = 0;<br /> for (int i = 0; i < len; i++) {<br /> hash = ((hash <<5) + hash) + (unsigned long) str[i];<br /> }<br /> return hash;<br /> }
59個字元1000 0000次運行(gcc沒有開啟最佳化,因為開了最佳化後兩個函數的實際代碼會一樣)

第一個:

real 0m4.389s
user 0m4.388s
sys 0m0.000s

第二個:

real 0m4.137s
user 0m4.120s
sys 0m0.000s

gcc –O2最佳化後是

real 0m1.367s
user 0m1.360s
sys 0m0.000s

php版本

59個字元,1000 0000次

real 0m1.088s
user 0m1.068s
sys 0m0.000s

速度提升主要在迴圈展開, 對於短字元,這個是不明顯的。

php版本的hash初始值是5381, 這個

Magic Constant 5381:

1. odd number

2. prime number

3. deficient number

4. 001/010/100/000/101 b
Apache版本

unsigned long time33(char const *str, int *len)<br />{<br /> unsigned long hash = 0;</p><p> const char *p=str;<br /> if (*len<=0) {<br /> for(p = str; *p; p++) {<br /> hash = hash * 33 + *p;<br /> }<br /> *len = p - str;<br /> }<br /> else {<br /> int i = *len;<br /> for (p = str;i; i--, p++) {<br /> hash = hash * 33 + *p;<br /> }<br /> }<br /> return hash;<br />}

測試結果

real 0m1.418s
user 0m1.412s
sys 0m0.004s

綜上,我的改進版本

#define likely(x) __builtin_expect((x),1)<br />#define unlikely(x) __builtin_expect((x),0)<br /> //php版本<br /> unsigned long time33(char const *str, int len=-1)<br /> {<br /> unsigned long hash = 5381;<br /> /* variant with the hash unrolled eight times */<br /> char const *p = str;<br /> if (unlikely(len<0)) {<br /> for(; *p; p++) {<br /> hash = hash * 33 + *p;<br /> }<br /> return hash;<br /> }</p><p>#define TIME33_HASH_MIXED_CH() hash = ((hash<<5)+hash) + *p++<br /> for (; len >= 8; len -= 8) {<br /> TIME33_HASH_MIXED_CH(); //1<br /> TIME33_HASH_MIXED_CH(); //2<br /> TIME33_HASH_MIXED_CH(); //3<br /> TIME33_HASH_MIXED_CH(); //4<br /> TIME33_HASH_MIXED_CH(); //5<br /> TIME33_HASH_MIXED_CH(); //6<br /> TIME33_HASH_MIXED_CH(); //7<br /> TIME33_HASH_MIXED_CH(); //8<br /> }<br /> switch (len) {<br /> case 7: TIME33_HASH_MIXED_CH(); /* fallthrough... */<br /> case 6: TIME33_HASH_MIXED_CH(); /* fallthrough... */<br /> case 5: TIME33_HASH_MIXED_CH(); /* fallthrough... */<br /> case 4: TIME33_HASH_MIXED_CH(); /* fallthrough... */<br /> case 3: TIME33_HASH_MIXED_CH(); /* fallthrough... */<br /> case 2: TIME33_HASH_MIXED_CH(); /* fallthrough... */<br /> case 1: TIME33_HASH_MIXED_CH(); break;<br /> case 0: break;<br /> }<br /> return hash;<br /> }

#undef TIME33_HASH_MIXED_CH
測試結果

real 0m1.072s
user 0m1.064s
sys 0m0.000s

測試過, 重複率在 1/2000。

為什麼是33的倍數, PHP中注釋是
DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
This is Daniel J. Bernstein's popular `times 33' hash function as
posted by him years ago on comp.lang.c. It basically uses a function
like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
known hash functions for strings. Because it is both computed very
fast and distributes very well.
The magic of number 33, i.e. why it works better than many other
constants, prime or not, has never been adequately explained by
anyone. So I try an explanation: if one experimentally tests all
multipliers between 1 and 256 (as RSE did now) one detects that even
numbers are not useable at all. The remaining 128 odd numbers
(except for the number 1) work more or less all equally well. They
all distribute in an acceptable way and this way fill a hash table
with an average percent of approx. 86%.
If one compares the Chi^2 values of the variants, the number 33 not
even has the best value. But the number 33 and a few other equally
good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
advantage to the remaining numbers in the large set of possible
multipliers: their multiply operation can be replaced by a faster
operation based on just one shift plus either a single addition
or subtraction operation. And because a hash function has to both
distribute good _and_ has to be very fast to compute, those few
numbers should be preferred and seems to be the reason why Daniel J.
Bernstein also preferred it.
-- Ralf S. Engelschall rse@engelschall.com
其它倍數
Ngix使用的是 time31
Tokyo Cabinet使用的是 time37

Bob在他的文章說,小寫英文詞彙適合33, 大小寫混合使用65。time33比較適合的是英文詞彙的hash.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.