हैशकोड में प्राइम नंबर का उपयोग क्यों करें?


174

मैं सोच रहा था कि क्लास के hashCode()तरीके में प्राइम का इस्तेमाल क्यों किया जाता है ? उदाहरण के लिए, मेरी hashCode()विधि उत्पन्न करने के लिए ग्रहण का उपयोग करते समय हमेशा 31उपयोग की जाने वाली अभाज्य संख्या होती है:

public int hashCode() {
     final int prime = 31;
     //...
}

संदर्भ:

यहां हैशकोड पर एक अच्छा प्राइमर है और हैशिंग कैसे काम करता है पर लेख (C # लेकिन अवधारणाएं हस्तांतरणीय हैं): एरिक लिपर्ट के दिशानिर्देश और गेटहॉशकोड के लिए नियम ()



यह कमोबेश प्रश्न stackoverflow.com/questions/1145217/… का डुप्लिकेट है ।
हंस-पीटर स्टॉर

1
कृपया stackoverflow.com/questions/1145217/… पर मेरे उत्तर की जाँच करें। यह एक क्षेत्र पर बहुपद के गुणों से संबंधित है (अंगूठी नहीं!), इसलिए अभाज्य संख्याएँ।
TT_

जवाबों:


104

क्योंकि आप चाहते हैं कि आप जिस संख्या से गुणा कर रहे हैं और आप जिस संख्या में बाल्टियाँ डाल रहे हैं, उनमें ऑर्थोगोनल प्राइम फैक्टर है।

मान लीजिए कि डालने के लिए 8 बाल्टी हैं। यदि आप जिस संख्या को गुणा करने के लिए उपयोग कर रहे हैं, वह कुछ 8 से अधिक है, तो इसमें डाली गई बाल्टी का निर्धारण केवल कम से कम महत्वपूर्ण प्रविष्टि (सभी में एक से गुणा नहीं) द्वारा किया जाएगा। इसी तरह की प्रविष्टियां टकराएंगी। हैश फ़ंक्शन के लिए अच्छा नहीं है।

31 एक बहुत बड़ा प्राइम है कि बाल्टी की संख्या इसके द्वारा विभाज्य होने की संभावना नहीं है (और वास्तव में, आधुनिक जावा हाशप कार्यान्वयन बाल्टी की संख्या को 2 की शक्ति तक रखता है)।


9
फिर एक हैश फ़ंक्शन जो 31 से गुणा करता है, गैर-आशावादी प्रदर्शन करेगा। हालाँकि, मैं इस तरह के हैश टेबल के कार्यान्वयन को खराब तरीके से तैयार करने पर विचार करूंगा, यह देखते हुए कि एक गुणक के रूप में आम 31 कैसे होता है।
ILMTitan

11
तो 31 को इस धारणा के आधार पर चुना गया है कि हैश तालिका के कार्यान्वयनकर्ता जानते हैं कि 31 का उपयोग आमतौर पर हैश कोड में किया जाता है?
स्टीव कू

3
31 को इस विचार के आधार पर चुना गया है कि अधिकांश कार्यान्वयन में अपेक्षाकृत छोटे अपराधों के कारक हैं। 2 एस, 3 एस और 5 एस आमतौर पर। यह 10 से शुरू हो सकता है और 3X बड़ा हो सकता है जब यह बहुत भरा हो जाता है। आकार शायद ही कभी पूरी तरह से यादृच्छिक है। और भले ही यह था, 30/31 अच्छी तरह से हैश एल्गोरिदम होने के लिए बुरा नहीं है। अन्य लोगों द्वारा बताई गई गणना करना भी आसान हो सकता है।
ILMTitan

8
दूसरे शब्दों में ... हमें इनपुट मानों के सेट और सेट की नियमितताओं के बारे में कुछ जानने की जरूरत है, ताकि एक ऐसा फ़ंक्शन लिखा जा सके जिसे उन नियमितताओं के लिए तैयार किया गया हो, इसलिए सेट में मौजूद मान आपस में टकराते नहीं हैं। हैश बाल्टी। प्राइम नंबर से गुणा / भाग करना / मोड्यूलिंग करना जो प्रभावित करता है, क्योंकि यदि आपके पास X- आइटम के साथ LOOP है और आप Y- रिक्त स्थान को लूप में कूदते हैं, तो आप कभी भी उसी स्थान पर नहीं लौटेंगे जब तक कि X, Y का कारक नहीं बन जाता। । चूँकि X अक्सर 2 की संख्या या शक्ति है, तो आपको Y की आवश्यकता होगी ताकि X + X + X अभाज्य हो ... Y का कारक नहीं है, इसलिए 31 याय है! : /
त्रिनको

3
@FrankQ। यह मॉड्यूलर अंकगणित की प्रकृति है। (x*8 + y) % 8 = (x*8) % 8 + y % 8 = 0 + y % 8 = y % 8
ILMTitan

135

प्राइम नंबर को हैश बकेट के बीच सबसे अच्छा डेटा वितरित करने के लिए चुना जाता है। यदि आदानों का वितरण यादृच्छिक है और समान रूप से फैला हुआ है, तो हैश कोड / मापांक का चुनाव कोई मायने नहीं रखता है। इसका केवल तभी प्रभाव पड़ता है जब इनपुट का एक निश्चित पैटर्न होता है।

स्मृति स्थानों से निपटने के दौरान अक्सर ऐसा होता है। उदाहरण के लिए, सभी 32-बिट पूर्णांकों को 4. द्वारा विभाज्य पतों के साथ संरेखित किया गया है। एक प्राइम बनाम गैर-प्राइम मापांक के उपयोग के प्रभावों की कल्पना करने के लिए नीचे दी गई तालिका देखें:

Input       Modulo 8    Modulo 7
0           0           0
4           4           4
8           0           1
12          4           5
16          0           2
20          4           6
24          0           3
28          4           0

प्राइम मापांक बनाम गैर-प्राइम मापांक का उपयोग करते समय लगभग-पूर्ण वितरण पर ध्यान दें।

हालांकि, हालांकि उपरोक्त उदाहरण काफी हद तक वंचित है, सामान्य सिद्धांत यह है कि इनपुट के पैटर्न के साथ काम करते समय , प्राइम नंबर मापांक का उपयोग करने से सबसे अच्छा वितरण होगा।


17
क्या हम हैश कोड उत्पन्न करने के लिए उपयोग किए जाने वाले गुणक के बारे में बात नहीं कर रहे हैं, न कि उन हैश कोड को बाल्टी में सॉर्ट करने के लिए उपयोग किए जाने वाले modulo?
ILMTitan

3
समान सिद्धांत। I / O के संदर्भ में, हैश तालिका के मॉडुलो ऑपरेशन में फ़ीड करता है। मुझे लगता है कि यदि आप अपराधों से गुणा करते हैं, तो आपको उस बिंदु पर अधिक यादृच्छिक रूप से वितरित इनपुट मिलेंगे जहां मॉडुलो की भी बात नहीं होगी। चूंकि हैश फंक्शन इनपुट्स को बेहतर तरीके से वितरित करने की सुस्त गति को चुनता है, जिससे वे कम नियमित हो जाते हैं, उनके टकराने की संभावना कम होती है, भले ही मोडुलो उन्हें एक बाल्टी में रखने के लिए इस्तेमाल करते हों।
त्रिकोको

9
इस तरह का उत्तर बहुत उपयोगी है क्योंकि यह किसी को मछली सिखाना पसंद है, न कि उनके लिए एक को पकड़ने के बजाय। यह लोगों को हैश के लिए primes का उपयोग करने के पीछे के अंतर्निहित सिद्धांत को देखने और समझने में मदद करता है ... जो कि अनियमित रूप से आदानों को वितरित करना है ताकि वे एक बार moduloed :) में समान रूप से बाल्टी में गिरें।
ट्राइंको

29

इसके लायक क्या है, गणित के मुद्दे के इर्द-गिर्द प्रभावी जावा द्वितीय संस्करण हाथ से छूटता है और बस यही कहना है कि 31 चुनने का कारण है:

  • क्योंकि यह एक अजीब प्राइम है, और यह primes का उपयोग करने के लिए "पारंपरिक" है
  • यह दो की शक्ति से भी कम है, जो बिटवाइज़ ऑप्टिमाइज़ेशन के लिए अनुमति देता है

आइटम 9hashCodeequals से पूर्ण उद्धरण यहां दिया गया है : जब आप ओवरराइड करते हैं तो हमेशा ओवरराइड करें :

मान 31 इसलिए चुना गया क्योंकि यह एक अजीब प्राइम है। यदि यह और भी गुणा किया गया था, तो जानकारी खो जाएगी, क्योंकि 2 से गुणा करना शिफ्टिंग के बराबर है। प्राइम का उपयोग करने का लाभ कम स्पष्ट है, लेकिन यह पारंपरिक है।

31 की एक अच्छी संपत्ति यह है कि गुणन को एक बदलाव ( 915.19 ) और बेहतर प्रदर्शन के लिए घटाव द्वारा प्रतिस्थापित किया जा सकता है :

 31 * i == (i << 5) - i

आधुनिक VM इस प्रकार का अनुकूलन स्वचालित रूप से करते हैं।


जबकि इस मद में नुस्खा बहुत अच्छा हैश कार्यों की पैदावार देता है, यह अत्याधुनिक हैश फ़ंक्शन का उत्पादन नहीं करता है, और न ही जावा प्लेटफ़ॉर्म लाइब्रेरी इस तरह के हैश कार्यों को रिलीज़ 1.6 के रूप में प्रदान करते हैं। इस तरह के हैश फ़ंक्शन लिखना एक शोध विषय है, जो गणितज्ञों और सैद्धांतिक कंप्यूटर वैज्ञानिकों के लिए सबसे अच्छा बचा है।

शायद मंच का एक बाद का विमोचन अपनी कक्षाओं और उपयोगिता विधियों के लिए अत्याधुनिक हैश फ़ंक्शन प्रदान करेगा ताकि औसत प्रोग्रामर ऐसे हैश फ़ंक्शंस का निर्माण कर सकें। इस बीच, इस आइटम में वर्णित तकनीकों को अधिकांश अनुप्रयोगों के लिए पर्याप्त होना चाहिए।

सरल रूप से, बल्कि यह कहा जा सकता है कि कई विभाजकों के साथ एक गुणक का उपयोग करने के परिणामस्वरूप अधिक हैश टकराव होंगे । चूंकि प्रभावी हैशिंग के कारण हम टकरावों की संख्या को कम करना चाहते हैं, हम ऐसे गुणक का उपयोग करने की कोशिश करते हैं जिसमें कम विभाजक हों। परिभाषा के अनुसार अभाज्य संख्या में दो अलग-अलग, सकारात्मक भाजक होते हैं।

संबंधित सवाल


4
एह, लेकिन ऐसे कई उपयुक्त प्राइम हैं जो या तो 2 ^ n + 1 हैं (जिन्हें फ़र्मेट प्राइम कहा जाता है ), 3, 5, 17, 257, 65537या 2 ^ n - 1 ( Mersenne primes ) 3, 7, 31, 127, 8191, 131071, 524287, 2147483647:। हालाँकि 31और नहीं, कहते हैं, 127) चुना है।
दिमित्री बर्नेंको

4
"क्योंकि यह एक अजीब प्राइम है" ... केवल एक भी प्राइम है: पी
मार्टिन श्नाइडर

मुझे यह पसंद नहीं है कि शब्द "कम स्पष्ट है, लेकिन यह" प्रभावी जावा "में पारंपरिक है"। यदि वह गणितीय विवरणों में नहीं जाना चाहता है, तो उसे कुछ ऐसा लिखना चाहिए जैसे "इसके समान" गणितीय कारण हैं "। जिस तरह से वह लिखते हैं, ऐसा लगता है कि केवल ऐतिहासिक पृष्ठभूमि थी :(
Qw3ry

5

मैंने सुना है कि 31 को चुना गया था ताकि कंपाइलर 5-बिट्स को लेफ्ट-शिफ्ट में गुणा कर सके और फिर मूल्य घटा सके।


कंपाइलर इस तरह से कैसे ऑप्टिमाइज़ कर सकता है? x * 31 == x * 32-1 सभी x afterall के लिए सही नहीं है। आपका मतलब क्या था 5 शिफ्ट छोड़ दिया गया (32 से गुणा बराबर) और फिर मूल मूल्य (मेरे उदाहरण में x) घटाएं। हालांकि यह तेज़ हो सकता है, फिर एक गुणा (यह आधुनिक तरीके से सीपीयू प्रोसेसर के लिए नहीं है), हैचकोड के लिए गुणा का चयन करते समय विचार करने के लिए अधिक महत्वपूर्ण कारक हैं (बाल्टी के लिए इनपुट मानों का समान वितरण दिमाग में आता है
ग्रिजली

थोड़ी खोज करें, यह एक आम राय है।
स्टीव कू

4
आम राय अप्रासंगिक है।
भग्न

1
@Grizzly, यह है तेजी से गुणा से। IMul ​​में किसी भी आधुनिक सीपीयू पर 3 चक्रों की न्यूनतम विलंबता है। (देखें एगो फॉग की नियमावली) mov reg1, reg2-shl reg1,5-sub reg1,reg22 चक्रों में निष्पादित हो सकती है। (मूव सिर्फ एक नाम है और 0 चक्र लेता है)।
जोहान

3

यहाँ एक उद्धरण स्रोत के थोड़ा करीब है।

यह करने के लिए नीचे फोड़े:

  • 31 प्रमुख है, जो टकराव को कम करता है
  • 31 एक अच्छा वितरण पैदा करता है, के साथ
  • गति में एक उचित tradeoff

3

सबसे पहले आप हैश मान modulo 2 ^ 32 (a) के आकार की गणना करते हैं int, इसलिए आप अपेक्षाकृत कुछ 2 ^ 32 (अपेक्षाकृत प्राइम का मतलब है कि कोई सामान्य विभाजक नहीं हैं) चाहते हैं। उसके लिए कोई भी विषम संख्या होगी।

फिर किसी दिए गए हैश टेबल के लिए इंडेक्स की गणना आमतौर पर हैश टेबल के आकार के हैश वैल्यू मोडुलो से की जाती है, इसलिए आप ऐसा कुछ चाहते हैं जो हैश टेबल के आकार के लिए अपेक्षाकृत प्रमुख हो। अक्सर हैश टेबल के आकार को उस कारण से प्रमुख संख्या के रूप में चुना जाता है। जावा के मामले में सूर्य कार्यान्वयन सुनिश्चित करता है कि आकार हमेशा दो की शक्ति है, इसलिए एक विषम संख्या यहां भी पर्याप्त होगी। टक्करों को और सीमित करने के लिए हैश कीज़ की कुछ अतिरिक्त मालिश करना भी है।

हैश टेबल और गुणक का एक सामान्य कारक nहोने पर बुरा प्रभाव यह हो सकता है कि कुछ परिस्थितियों में हैश तालिका में केवल 1 / n प्रविष्टियों का उपयोग किया जाएगा।


2

जब प्राइम नंबर का उपयोग किया जाता है तो इसका कारण टकराव को कम करना होता है जब डेटा कुछ विशेष पैटर्न प्रदर्शित करता है।

पहली चीजें पहले: यदि डेटा यादृच्छिक है तो प्राइम नंबर की कोई आवश्यकता नहीं है, आप किसी भी संख्या के खिलाफ एक मॉड ऑपरेशन कर सकते हैं और आपके पास मापांक के प्रत्येक संभावित मूल्य के लिए समान संख्या में टकराव होंगे।

लेकिन जब डेटा यादृच्छिक नहीं होता है तो अजीब चीजें होती हैं। उदाहरण के लिए संख्यात्मक डेटा पर विचार करें जो हमेशा 10 का गुणक होता है।

यदि हम mod 4 का उपयोग करते हैं तो हम पाते हैं:

10 मॉड 4 = 2

20 मॉड 4 = 0

30 मॉड 4 = 2

40 मॉड 4 = 0

50 मॉड 4 = 2

इसलिए मापांक के 3 संभावित मानों (0,1,2,3) से केवल 0 और 2 में टकराव होगा, यह बुरा है।

अगर हम 7 जैसी एक अभाज्य संख्या का उपयोग करते हैं:

10 मॉड 7 = 3

20 आधुनिक 7 = 6

30 मॉड 7 = 2

40 मॉड 7 = 4

50 मॉड 7 = 1

आदि

हम यह भी ध्यान देते हैं कि 5 एक अच्छा विकल्प नहीं है, लेकिन 5 प्रमुख कारण यह है कि हमारी सभी चाबियाँ 5 से अधिक हैं। इसका मतलब है कि हमें एक अभाज्य संख्या चुननी होगी, जो हमारी कुंजियों को विभाजित न करे, एक बड़ी अभाज्य संख्या का चयन करना है। आमतौर पर पर्याप्त है।

तो पुनरावृत्ति होने के पक्ष में ग़लती के कारण अभाज्य संख्याओं का उपयोग होता है, जो हैश फ़ंक्शन के टकरावों के वितरण में कुंजियों में पैटर्न के प्रभाव को बेअसर करता है।


1

31 जावा हाशप के लिए भी विशिष्ट है जो हैश डेटा प्रकार के रूप में एक इंट का उपयोग करता है। इस प्रकार 2 ^ 32 की अधिकतम क्षमता। बड़े फ़र्मेट या मेर्सेन प्राइम का उपयोग करने का कोई मतलब नहीं है।


0

यह आम तौर पर हैश बाल्टी के बीच अपने डेटा के अधिक प्रसार को प्राप्त करने में मदद करता है, विशेष रूप से कम-एन्ट्रोपी कुंजी के लिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.