जवाबों:
नुथ की गुणन विधि:
hash(i)=i*2654435761 mod 2^32
सामान्य तौर पर, आपको एक गुणक चुनना चाहिए जो आपके हैश आकार ( 2^32
उदाहरण में) के क्रम में है और इसके साथ कोई सामान्य कारक नहीं है। इस तरह से हैश फंक्शन आपके सभी हैश स्पेस को समान रूप से कवर करता है।
संपादित करें: इस हैश फ़ंक्शन का सबसे बड़ा नुकसान यह है कि यह विभाज्यता को संरक्षित करता है, इसलिए यदि आपके पूर्णांक 2 या 4 से विभाज्य हैं (जो असामान्य नहीं है), तो उनका हैश भी होगा। यह हैश तालिकाओं में एक समस्या है - आप उपयोग की जा रही बाल्टियों के केवल 1/2 या 1/4 के साथ समाप्त कर सकते हैं।
मैंने पाया कि निम्नलिखित एल्गोरिथ्म एक बहुत अच्छा सांख्यिकीय वितरण प्रदान करता है। प्रत्येक इनपुट बिट लगभग 50% प्रायिकता के साथ प्रत्येक आउटपुट बिट को प्रभावित करता है। कोई टक्कर नहीं है (प्रत्येक इनपुट एक अलग आउटपुट में परिणाम)। यदि सीपीयू में अंतर्निहित पूर्णांक गुणन इकाई नहीं है तो सिवाय एल्गोरिथ्म तेज है। सी कोड, संभालने के int
लिए 32 बिट (जावा के लिए, के >>
साथ बदलें >>>
और निकालें unsigned
):
unsigned int hash(unsigned int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
मैजिक नंबर की गणना एक विशेष मल्टी-थ्रेडेड टेस्ट प्रोग्राम का उपयोग करके की गई थी जो कई घंटों तक चलता था, जो हिमस्खलन प्रभाव की गणना करता है (आउटपुट बिट्स की संख्या जो एकल इनपुट बिट बदल जाती है; औसतन लगभग 16 होनी चाहिए), स्वतंत्रता आउटपुट बिट परिवर्तन (आउटपुट बिट्स एक दूसरे पर निर्भर नहीं होना चाहिए), और यदि कोई इनपुट बिट बदला जाता है तो प्रत्येक आउटपुट बिट में बदलाव की संभावना। गणना किए गए मान मुरमुरैश द्वारा उपयोग किए जाने वाले 32-बिट फाइनल से बेहतर हैं , और एईएस का उपयोग करते समय लगभग (जितना अच्छा नहीं) । एक मामूली लाभ यह है कि एक ही निरंतर का उपयोग दो बार किया जाता है (यह पिछली बार जब मैंने परीक्षण किया तो यह थोड़ा तेज हो गया, यकीन नहीं होता कि यह अभी भी मामला है)।
यदि आप ( गुणक प्रतिलोम ) के 0x45d9f3b
साथ प्रतिस्थापित करते हैं, तो आप प्रक्रिया को उल्टा कर सकते हैं (हैश से इनपुट मान प्राप्त करें ):0x119de1f3
unsigned int unhash(unsigned int x) {
x = ((x >> 16) ^ x) * 0x119de1f3;
x = ((x >> 16) ^ x) * 0x119de1f3;
x = (x >> 16) ^ x;
return x;
}
64-बिट संख्या के लिए, मैं निम्नलिखित का उपयोग करने का सुझाव देता हूं, यहां तक कि सोचा कि यह सबसे तेज़ नहीं हो सकता है। यह एक स्प्लिटमिक्स 64 पर आधारित है , जो ब्लॉग के लेख बेटर बिट मिक्सिंग (मिक्स 13) पर आधारित लगता है ।
uint64_t hash(uint64_t x) {
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
x = x ^ (x >> 31);
return x;
}
जावा के लिए, का उपयोग करें long
, L
निरंतर में जोड़ें , के >>
साथ बदलें >>>
और निकालें unsigned
। इस मामले में, पलटाव अधिक जटिल है:
uint64_t unhash(uint64_t x) {
x = (x ^ (x >> 31) ^ (x >> 62)) * UINT64_C(0x319642b2d24d8ec3);
x = (x ^ (x >> 27) ^ (x >> 54)) * UINT64_C(0x96de1b173f119089);
x = x ^ (x >> 30) ^ (x >> 60);
return x;
}
अद्यतन: आप हैश फंक्शन प्रॉस्पेक्टर प्रोजेक्ट को भी देखना चाहते हैं , जहाँ अन्य (संभवतः बेहतर) स्थिरांक सूचीबद्ध हैं।
x = ((x >> 32) ^ x)
और फिर ऊपर 32 बिट गुणा का उपयोग करें। मुझे यकीन नहीं है कि बेहतर क्या है। आप मुरमुर 3 के लिए 64-बिट फ़ाइनलीज़र
निर्भर करता है कि आपका डेटा कैसे वितरित किया जाता है। एक सरल काउंटर के लिए, सबसे सरल फ़ंक्शन
f(i) = i
अच्छा होगा (मुझे इष्टतम पर संदेह है, लेकिन मैं इसे साबित नहीं कर सकता)।
तेज और अच्छे हैश कार्यों को कम गुणों के साथ तेजी से क्रमपरिवर्तन से बनाया जा सकता है, जैसे
बेहतर गुणों के साथ एक हैशिंग फ़ंक्शन का उत्पादन करने के लिए, जैसे यादृच्छिक संख्या पीढ़ी के लिए पीसीजी के साथ प्रदर्शन किया गया ।
यह वास्तव में रेसिपी rrxmrxmsx_0 है और बड़बड़ाहट हैश जानबूझकर या अनजाने में उपयोग कर रहे हैं।
मैं व्यक्तिगत रूप से मिला
uint64_t xorshift(const uint64_t& n,int i){
return n^(n>>i);
}
uint64_t hash(const uint64_t& n){
uint64_t p = 0x5555555555555555ull; // pattern of alternating 0 and 1
uint64_t c = 17316035218449499591ull;// random uneven integer constant;
return c*xorshift(p*xorshift(n,32),32);
}
काफी अच्छा है।
एक अच्छा हैश फ़ंक्शन होना चाहिए
आइए सबसे पहले आइडेंटिटी फंक्शन देखें। यह 1. संतुष्ट करता है, लेकिन 2. नहीं:
इनपुट बिट n 100% (लाल) के सहसंबंध के साथ आउटपुट बिट n निर्धारित करता है और कोई अन्य नहीं, इसलिए वे नीले हैं, जो संपूर्ण लाल रेखा को पार करते हैं।
एक xorshift (n, 32) ज्यादा बेहतर नहीं है, एक और आधी लाइन की पैदावार। अभी भी संतोषजनक 1., क्योंकि यह एक दूसरे अनुप्रयोग के साथ उलटा है।
एक अहस्ताक्षरित पूर्णांक के साथ एक गुणन बहुत बेहतर होता है, अधिक मजबूती से कैस्केडिंग करता है और 0.5 की संभावना के साथ अधिक आउटपुट बिट्स को फ्लिप करता है, जो कि आप चाहते हैं, हरे रंग में। यह 1 को संतुष्ट करता है। प्रत्येक असमान पूर्णांक के लिए एक गुणात्मक व्युत्क्रम होता है।
दो को मिलाने से निम्न आउटपुट प्राप्त होता है, फिर भी संतोषजनक 1। दो विशेषण कार्यों की संरचना के कारण एक और विशेषण फलित होता है।
गुणन और xorshift का एक दूसरा आवेदन निम्नलिखित प्राप्त करेगा:
या आप गलास जैसे गुणेश क्षेत्र गुणकों का उपयोग कर सकते हैं , वे आधुनिक सीपीयू पर यथोचित रूप से तेज़ हो गए हैं और एक चरण में बेहतर गुण हैं।
uint64_t const inline gfmul(const uint64_t& i,const uint64_t& j){
__m128i I{};I[0]^=i;
__m128i J{};J[0]^=j;
__m128i M{};M[0]^=0xb000000000000000ull;
__m128i X = _mm_clmulepi64_si128(I,J,0);
__m128i A = _mm_clmulepi64_si128(X,M,0);
__m128i B = _mm_clmulepi64_si128(A,M,0);
return A[0]^A[1]^B[1]^X[0]^X[1];
}
__m128i I = i; //set the lower 64 bits
, लेकिन मैं ऐसा नहीं कर सकता, इसलिए मैं उपयोग कर रहा हूं ^=
। 0^1 = 1
इसलिए कोई अवांछित नहीं है। साथ initialisation के बारे में {}
कभी नहीं शिकायत की मेरी संकलक, यह सबसे अच्छा समाधान नहीं हो सकता है, लेकिन क्या मैं उस के साथ चाहते हैं 0 को इसके बारे में सब आरंभ है तो मैं क्या कर सकते हैं ^=
या |=
। मुझे लगता है कि मैं इस ब्लॉगपोस्ट पर उस कोड को आधारित करता हूं, जो उलटा भी देता है, बहुत उपयोगी है: डी
यह पृष्ठ कुछ सरल हैश फ़ंक्शन को सूचीबद्ध करता है जो सामान्य रूप से शालीनता से करते हैं, लेकिन किसी भी सरल हैश में पैथोलॉजिकल मामले हैं जहां यह अच्छी तरह से काम नहीं करता है।
32-बिट गुणक विधि (बहुत तेज) @ अराफाल देखें
#define hash32(x) ((x)*2654435761)
#define H_BITS 24 // Hashtable size
#define H_SHIFT (32-H_BITS)
unsigned hashtab[1<<H_BITS]
....
unsigned slot = hash32(x) >> H_SHIFT
32-बिट्स और 64-बिट्स (अच्छा वितरण) पर: मुरमुराश
अनंत काल में कुछ हैश एल्गोरिदम पर एक अच्छा अवलोकन है । मैं बॉब जेनकींस की एक-पर-एक-समय हैश की सिफारिश करूंगा, जो जल्दी से हिमस्खलन तक पहुंच जाता है और इसलिए इसे कुशल हैशट टेबल लुकअप के लिए इस्तेमाल किया जा सकता है।
जवाब बहुत सी बातों पर निर्भर करता है जैसे:
मेरा सुझाव है कि आप SHA-1 इत्यादि जैसे हैश कार्यों के मर्कले-डमगार्ड परिवार पर एक नज़र डालें
मुझे नहीं लगता कि हम कह सकते हैं कि एक हैश फ़ंक्शन आपके डेटा को अग्रिम में जानने के बिना "अच्छा" है! और यह जाने बिना कि आप इसके साथ क्या करने जा रहे हैं।
अज्ञात डेटा आकारों के लिए हैश टेबल की तुलना में बेहतर डेटा संरचनाएं हैं (मैं मान रहा हूं कि आप यहां हैश टेबल के लिए हैशिंग कर रहे हैं)। मैं व्यक्तिगत रूप से एक हैश टेबल का उपयोग करूंगा जब मुझे पता चलेगा कि मेरे पास "परिमित" तत्वों की संख्या है जिन्हें स्मृति की सीमित मात्रा में संग्रहित करने की आवश्यकता है। मैं अपने डेटा पर त्वरित सांख्यिकीय विश्लेषण करने की कोशिश करूँगा, यह देखूंगा कि मेरे हैश फ़ंक्शन के बारे में सोचने से पहले इसे कैसे वितरित किया जाता है आदि।
यादृच्छिक हैश मूल्यों के लिए, कुछ इंजीनियरों ने कहा कि स्वर्ण अनुपात अभाज्य संख्या (2654435761) एक बुरा विकल्प है, मेरे परीक्षण परिणामों के साथ, मैंने पाया कि यह सच नहीं है; इसके बजाय, 2654435761 हैश मूल्यों को बहुत अच्छा वितरित करता है।
#define MCR_HashTableSize 2^10
unsigned int
Hash_UInt_GRPrimeNumber(unsigned int key)
{
key = key*2654435761 & (MCR_HashTableSize - 1)
return key;
}
हैश टेबल का आकार दो की शक्ति होना चाहिए।
मैंने पूर्णांक के लिए कई हैश फ़ंक्शन का मूल्यांकन करने के लिए एक परीक्षण कार्यक्रम लिखा है, परिणाम बताते हैं कि GRPrimeNumber एक बहुत अच्छा विकल्प है।
मैंने कोशिश की है:
अपने परीक्षण परिणामों के साथ, मैंने पाया कि गोल्डन रेशियो प्राइम नंबर में हमेशा कम खाली बाल्टी या शून्य खाली बाल्टी और सबसे छोटी कोलरी श्रृंखला की लंबाई होती है।
पूर्णांकों के लिए कुछ हैश फ़ंक्शन अच्छे होने का दावा किया जाता है, लेकिन परीक्षण के परिणाम बताते हैं कि जब कुल_data_entry / total_bucket_number = 3, सबसे लंबी श्रृंखला की लंबाई 10 (अधिकतम टकराव की संख्या> 10) से अधिक होती है, और कई बाल्टी मैप नहीं की जाती हैं (खाली बाल्टी ), जो कि गोल्डन रैट प्राइम नंबर हाशिंग द्वारा शून्य खाली बाल्टी और सबसे लंबी श्रृंखला लंबाई 3 के परिणाम की तुलना में बहुत खराब है।
BTW, मेरे परीक्षण परिणामों के साथ, मैंने पाया कि शिफ्टिंग-एक्सआर हैश फ़ंक्शन का एक संस्करण बहुत अच्छा है (यह मीकेरा द्वारा साझा किया गया है)।
unsigned int Hash_UInt_M3(unsigned int key)
{
key ^= (key << 13);
key ^= (key >> 17);
key ^= (key << 5);
return key;
}
मैं splitmix64
(थॉमस मुलेर के उत्तर में इंगित ) का उपयोग कर रहा हूं जब से मैंने यह धागा पाया है। हालाँकि, मैंने हाल ही में पेले इवेंसन के rxxrrxmsx_0 पर ठोकर खाई , जो मूल मुरमुरश 3 फाइनल और उसके उत्तराधिकारियों ( splitmix64
और अन्य मिक्स) की तुलना में काफी बेहतर सांख्यिकीय वितरण प्राप्त हुआ । यहाँ C में कोड स्निपेट है:
#include <stdint.h>
static inline uint64_t ror64(uint64_t v, int r) {
return (v >> r) | (v << (64 - r));
}
uint64_t rrxmrrxmsx_0(uint64_t v) {
v ^= ror64(v, 25) ^ ror64(v, 50);
v *= 0xA24BAED4963EE407UL;
v ^= ror64(v, 24) ^ ror64(v, 49);
v *= 0x9FB21C651E98DF25UL;
return v ^ v >> 28;
}
पेले 64-बिट मिक्सर के अंतिम चरण में और अधिक हाल के वेरिएंट में उपयोग किए गए गहन विश्लेषण भी प्रदान करता है MurmurHash3
।