2010-06-28 19 views
14

Cactus Kev's Poker Hand Evaluator के माध्यम से पढ़ना, मैं निम्नलिखित बयानों देखा:जो तेजी से है - तत्वों की एक छोटी सरणी को सॉर्ट करना या गुणा करना?

सबसे पहले, मैंने सोचा था कि मैं हमेशा बस पहले यह मूल्यांकनकर्ता को पार करने से पहले हाथ को सॉर्ट कर सकता है; लेकिन सॉर्टिंग में समय लगता है, और मैं हाथों को सॉर्ट करने वाले किसी भी CPU चक्र को बर्बाद नहीं करना चाहता था। मुझे एक ऐसी विधि की आवश्यकता थी जिस पर ध्यान नहीं दिया गया कि पांच कार्ड किस क्रम के रूप में दिए गए थे।
...
बहुत सारे विचारों के बाद, मुझे मुख्य संख्याओं का उपयोग करने के लिए एक बुद्धिमान था। मैं तेरह कार्ड रैंकों में से प्रत्येक के लिए एक प्राइम नंबर वैल्यू असाइन करूंगा ... इस प्रणाली की सुंदरता यह है कि यदि आप अपने हाथ में प्रत्येक कार्ड के रैंक के प्राइम वैल्यू गुणा करते हैं, तो ऑर्डर के बावजूद आपको एक अद्वितीय उत्पाद मिलता है पांच कार्डों में से।
...
हमारे समय मिलीसेकंड के बाद से गुणा सबसे तेजी से गणना एक कंप्यूटर बना सकते हैं में से एक है, हम मुंडा है सैकड़ों हम मूल्यांकन से पहले प्रत्येक हाथ सॉर्ट करने के लिए मजबूर किया गया था।

मुझे इस पर विश्वास करने में कठिन समय है।

कैक्टस केवी प्रत्येक कार्ड को 4-बाइट पूर्णांक के रूप में दर्शाता है, और eval_5cards(int c1, int c2, int c3, int c4, int c5) पर कॉल करके हाथों का मूल्यांकन करता है। हम एक बाइट के रूप में कार्ड और 5-बाइट सरणी के रूप में पोकर हाथ का प्रतिनिधित्व कर सकते हैं। एक अद्वितीय हाथ पाने के लिए इस 5-बाइट सरणी को सॉर्ट करना बहुत तेज़ होना चाहिए। क्या यह उनके दृष्टिकोण से तेज़ है?

क्या होगा यदि हम उसका प्रतिनिधित्व (4-बाइट पूर्णांक के रूप में कार्ड) रखें? 5 पूर्णांक की सरणी को सॉर्ट करने से उन्हें गुणा करने से तेज़ हो सकता है? यदि नहीं, तो तत्वों की एक छोटी संख्या को क्रमबद्ध करने के लिए किस तरह के निम्न-स्तरीय अनुकूलन किए जा सकते हैं?

धन्यवाद!

सभी को अच्छा जवाब दें; मैं कुछ कठिन प्रदर्शन आंकड़े प्राप्त करने के लिए सॉर्टिंग बनाम गुणा के प्रदर्शन को बेंचमार्किंग पर काम कर रहा हूं।

+0

उसे गुणा का उपयोग करने की भी आवश्यकता नहीं है - अतिरिक्त रूप से अच्छी तरह से काम करने के लिए जोड़ा जा सकता है (रैंक का प्रतिनिधित्व करने के लिए संख्याओं के एक अलग चयन के साथ)। यह अनिवार्य रूप से केवल एक हैश फ़ंक्शन है जो इनपुट आइटम के पुनर्वितरण के तहत परिवर्तनीय है। – caf

+0

याद रखें कि गुणा हार्डवेयर पर किया जाने वाला एक प्रारंभिक ऑपरेशन है, उसकी कहानी में योग्यता हो सकती है। ध्यान दें कि यह अनिवार्य रूप से हैशिंग है (उसका हैशिंग फ़ंक्शन एक-टू-वन है जिसे वास्तव में तेज़ गणना किया जा सकता है) – ldog

+0

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

उत्तर

5

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

हालांकि, पोकर हाथ एक एसिम्प्टोटिक समस्या नहीं है। यह सिर्फ 5 कार्ड है और वह केवल कार्ड के 13 नंबरों में से एक के बारे में परवाह करता है। भले ही गुणा सिद्धांत में जटिल है, प्रैक्टिस में इसे माइक्रोकोड में कार्यान्वित किया जाता है और यह अविश्वसनीय रूप से तेज़ है। वह क्या कर रहा है।

अब, यदि आप सैद्धांतिक प्रश्न में रुचि रखते हैं, तो गुणा के बजाय अतिरिक्त उपयोग का समाधान भी है। केवल एक ही मूल्य के 4 कार्ड हो सकते हैं, इसलिए आप मूल्यों को भी 1,5,25, ..., 5^12 असाइन कर सकते हैं और उन्हें जोड़ सकते हैं। यह अभी भी 32-बिट अंकगणित में फिट बैठता है। अन्य गणितीय गुणों के साथ अन्य अतिरिक्त-आधारित समाधान भी हैं। लेकिन यह वास्तव में कोई फर्क नहीं पड़ता, क्योंकि माइक्रोकोडेड अंकगणित कंप्यूटर कुछ भी कर रहा है उससे कहीं ज्यादा तेज़ है।

6

परीक्षण के बिना, मैं उनके तर्क से सहानुभूति व्यक्त करता हूं। सॉर्टिंग की तुलना में आप इसे 4 गुणाओं में कर सकते हैं, जो n log n है। विशेष रूप से, इष्टतम sorting network 9 तुलना की आवश्यकता है। मूल्यांकनकर्ता को कम से कम क्रमबद्ध सरणी के प्रत्येक तत्व को देखना होगा, जो कि एक और 5 संचालन है।

+20

बिग ओ जटिलता पूरी तरह से अप्रासंगिक है जब आप एक निश्चित n = 5 –

+2

के बारे में बात कर रहे हैं, जबकि प्रश्न पाठ 5 के लिए विशिष्ट है, शीर्षक सामान्य रूप से छोटे सरणी के बारे में पूछता है। वैसे भी, मैंने इस उदाहरण के लिए आवश्यक तुलना की सटीक संख्या में डाल दिया है। –

+5

स्टैक पर 4 इन्स आवंटित करने से पॉइंटर को बढ़ाकर किया जा सकता है। यह शायद ही कभी बाधा होने की संभावना है। –

1

यह वास्तव में प्रासंगिक नहीं होना चाहिए, लेकिन वह सही है। सॉर्टिंग गुणा करने से ज्यादा लंबा लगता है।

असली सवाल क्या वह जिसके परिणामस्वरूप अभाज्य संख्या के साथ किया था, और कहा कि कैसे मददगार था है (यह बाँटे के बाद से मैं छँटाई से अधिक समय लग की उम्मीद करेंगे।

+0

अगर मुझे सही याद है, तो उसने इसे एक विशाल तालिका में लुकअप के रूप में इस्तेमाल किया। – AShelly

+1

वह 2,558,960 अद्वितीय पांच-कार्ड पोकर हाथों में से प्रत्येक को केवल 7462 विशिष्ट मानों में से एक में मैप कर रहा है। एक [समकक्ष संबंध] की तरह (http://en.wikipedia.org/wiki/Equivalence_relation)। – Rudiger

+0

असम्बद्ध रूप से, सॉर्टिंग गुणा करने से काफी अधिक समय लेता है। यह असीमोटिक प्रदर्शन के विपरीत काफी सुंदर है! – Rudiger

1

यह किसी भी छँटाई आपरेशन कि हो सकता है के बारे में सोचना मुश्किल है संख्याओं के समान सेट को गुणा करने से तेज़। प्रोसेसर स्तर पर, गुणा केवल load, load, multiply, load, multiply, ... है, शायद इसमें जमा किए गए संचयक के कुछ हेरफेर के साथ। यह रैखिक, आसानी से पाइपलाइन है, संबंधित शाखा गलत भविष्यवाणी लागतों के साथ कोई तुलना नहीं है। गुणा करने के लिए प्रति मान के बारे में 2 निर्देश। जब तक गुणा निर्देश दर्दनाक रूप से धीमा नहीं होता है, तब तक तेजी से कल्पना करना मुश्किल होता है।

+0

किसी प्रकार के मेमोरी एक्सेस पैटर्न को +1 करता है (और mov/load आमतौर पर गुणा करने से कहीं धीमा हो जाएगा) एक साथ 5 इंटीग्रल को गुणा करने के समान तेज़ होने की संभावना नहीं है। – stinky472

6

बेशक यह आपके कंप्यूटर के सीपीयू पर बहुत निर्भर करता है, लेकिन एक विशिष्ट इंटेल सीपीयू (उदा। कोर 2 डुओ) 3 सीपीयू घड़ी चक्रों के भीतर दो 32 बिट संख्याओं को गुणा कर सकता है। एक प्रकार के एल्गोरिदम के लिए इसे हरा करने के लिए, एल्गोरिदम को 3 * 4 = 12 CPU चक्रों से तेज़ होना चाहिए, जो एक बहुत तंग बाधा है। मानक सॉर्टिंग एल्गोरिदम में से कोई भी इसे सुनिश्चित करने के लिए 12 चक्र से कम में नहीं कर सकता है।अकेले दो नंबरों की तुलना में एक सीपीयू चक्र लगेगा, नतीजे पर सशर्त शाखा एक सीपीयू चक्र भी लेगी और जो कुछ भी आप करेंगे, कम से कम एक सीपीयू चक्र लेंगे (दो कार्ड्स को स्वैप करना वास्तव में कम से कम 4 सीपीयू चक्र लेगा)। तो जीत गुणा।

बेशक यह कार्ड या तो पहले या दूसरे स्तर के कैश या यहां तक ​​कि स्मृति से कार्ड मूल्य लाने के लिए विलंबता नहीं ले रहा है; हालांकि, यह विलंबता किसी भी मामले, गुणा और सॉर्टिंग पर लागू होती है।

+0

उसे कार्ड मूल्य लाने और 13 प्राइम्स की सूची में लुकअप करने की आवश्यकता है। सॉर्टिंग से अभी भी तेज है। – phkahler

+0

इस तथ्य को ध्यान में रखते हुए, कि एक या दो लुकअप के बाद 13 प्राइम पहली स्तर के कैश में सबसे अधिक संभावना है, यह प्रत्येक कार्ड के लुकअप के लिए एक और 3 घड़ी चक्र जोड़ देगा। लेकिन आप सही हैं, यह अभी भी निश्चित रूप से तेज़ है। – Mecki

+1

जबकि बिंदु अच्छा है, आपका चक्र गिनती थोड़ा सा प्रतीत होता है। गुणात्मक मामले के लिए, गुणों में से एक को पाइपलाइन किया जा सकता है, इसलिए विलंबता 9 चक्र है। गलत भविष्यवाणियों के कारण सशर्त शाखाएं औसतन 1 चक्र से अधिक लेती हैं। सीएमओवी डेटा-निर्भरताओं में नियंत्रण प्रवाह को बदल सकता है, लेकिन यहां तक ​​कि पाइपलाइनिंग के लिए लेखांकन, इष्टतम सॉर्टिंग नेटवर्क के लिए सीएमओवी के = 11 चक्रों के लिए सीएमपी + 5 * 2 चक्रों के लिए सबसे अच्छा मामला 1 चक्र है। –

2

5 तत्वों को एक अनुकूलित निर्णय पेड़ का उपयोग करके सॉर्ट किया जा सकता है, जो एक सामान्य उद्देश्य सॉर्टिंग एल्गोरिदम का उपयोग करने से बहुत तेज है।

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

लेकिन अगर आप सॉर्टिंग करने के लिए कस्टम हार्डवेयर बना सकते हैं, तो तेज हो सकता है।

+0

एक विशेष रेडिक्स सॉर्ट बहुत तेज़ और शाखा रहित होगा। – Dolphin

1

उल्लेख करने योग्य एक बात यह है कि भले ही आपके सीपीयू के गुणा निर्देश धीमे हो जाएं (या nonexistent ...) आप चीजों को और भी गति देने के लिए एक लुकअप टेबल का उपयोग कर सकते हैं।

+0

7-कार्ड मूल्यांकनकर्ता वास्तव में 7 कार्ड्स के संभावित संयोजन (लगभग 130,000,000 संयोजन) के लिए हाथ रैंक का प्रतिनिधित्व करने वाले पेड़ को लोड करने के लिए करता है। यह बहुत तेज है लेकिन शुरू करने के लिए कई सौ मेगा रैम और लोड समय लेता है। – stinky472

1

बहुत सारे विचारों के बाद, मुझे मुख्य संख्याओं का उपयोग करने के लिए एक बुद्धिमानी थी। मैं तेरह कार्ड रैंकों में से प्रत्येक के लिए एक प्राइम नंबर वैल्यू असाइन करूंगा ... इस प्रणाली की सुंदरता यह है कि यदि आप अपने हाथ में प्रत्येक कार्ड के रैंक के प्राइम वैल्यू गुणा करते हैं, तो ऑर्डर के बावजूद आपको एक अद्वितीय उत्पाद मिलता है पांच कार्डों में से।

यह एक गैर-स्थितित्मक संख्या प्रणाली का एक उदाहरण है।

मुझे सिद्धांत के लिंक नहीं मिल रहे हैं। मैंने अध्ययन किया कि लागू बीजगणित के हिस्से के रूप में, यूलर के कुल और एन्क्रिप्शन के आसपास कहीं। (मैं शब्दावली के साथ गलत हो सकता हूं क्योंकि मैंने अपनी मूल भाषा में सब कुछ पढ़ा है।)

क्या होगा यदि हम उसका प्रतिनिधित्व (4-बाइट पूर्णांक के रूप में कार्ड) रखें? 5 पूर्णांक की सरणी को सॉर्ट करने से उन्हें गुणा करने से तेज़ हो सकता है?

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

मुझे लगता है कि आधुनिक सीपीयू पूर्णांक गुणा पर सॉर्टिंग की तुलना में काफी तेज़ होगा, क्योंकि कई गुणाओं को अलग-अलग एएलयू पर एक ही समय में निष्पादित किया जा सकता है, जबकि सीपीयू को रैम से कनेक्ट करने वाली केवल एक बस है।

यदि नहीं, तो तत्वों की एक छोटी संख्या को क्रमबद्ध करने के लिए किस तरह के निम्न-स्तर अनुकूलन किए जा सकते हैं?

5 पूर्णांकों बहुत जल्दी हल हो सकता है का उपयोग कर bubble sort: qsort अधिक स्मृति (प्रत्यावर्तन के लिए) का प्रयोग करेंगे, जबकि अच्छी तरह से अनुकूलित बुलबुला तरह डी-कैश से पूरी तरह से काम करेगा।

+2

"स्वैप संचालन के कारण 5 इंच की छंटनी को हमेशा रैम पर जाना होगा।" - आप किस प्रकार के सीपीयू का उपयोग कर रहे हैं, जिसमें केवल 5 32-बिट रजिस्ट्रार हैं? उल्लेख नहीं है, रजिस्टरों से अगला कदम नीचे एल 1 कैश है, रैम नहीं। –

+0

@ निक, कोई कंपाइलर रजिस्टरों में चर लंबाई के साथ एक सरणी को कैश करने का प्रयास करेगा। जब तक निश्चित सरणी लंबाई के साथ कस्टम फ़ंक्शन का उपयोग नहीं किया जाता है। और, हाँ, मैंने स्मृति संगठन के विवरण पर थोड़ा ब्रश किया है। कैश-लाइन-संरेखण/i $/d $/L1/L2/L3/TLB/शाखा-पूर्वानुमान/कैश-राइट-थ्रू में जाकर स्पष्टीकरण को अनावश्यक रूप से जटिल बना दिया जाएगा। सामान्य नियम है: कम महंगे संसाधनों का उपयोग किया जाता है, बेहतर। और स्मृति महंगा है। बहुत छोटी सरणी लंबाई पर, qsort() की रिकर्सन मेमोरी ओवरहेड बस डिचोटोमी के लाभ से अधिक है। – Dummy00001

+0

किसी ने भी नहीं कहा कि आपको एक सरणी और एक सामान्य सॉर्टिंग एल्गोरिदम का उपयोग करना था, हालांकि। वास्तव में, कई लोगों ने सॉर्टिंग नेटवर्क का सुझाव दिया है। और जैसा कि मैंने कहा, अगला स्तर नीचे कैश है, रैम नहीं। –

0

जैसा कि अन्य ने इंगित किया है, अकेले सॉर्ट करना 5 मानों के लिए गुणा करने से तेज़ नहीं है। यह, उसके बाकी समाधान, हालांकि, अनदेखा करता है। 5-तत्व प्रकार को रद्द करने के बाद, वह 4888 मूल्यों की एक सरणी पर एक द्विआधारी खोज करने के लिए आगे बढ़ता है - कम से कम 12 तुलना, कभी भी आवश्यकतानुसार अधिक!

ध्यान दें कि मैं यह नहीं कह रहा हूं कि एक बेहतर समाधान है जिसमें सॉर्टिंग शामिल है - मैंने इसे पर्याप्त विचार नहीं दिया है, व्यक्तिगत रूप से - केवल यह कि अकेला सॉर्टिंग केवल समस्या का हिस्सा है।

उन्हें भी प्राइम का उपयोग करने की आवश्यकता नहीं थी। अगर उसने 4 बिट्स में प्रत्येक कार्ड के मूल्य को एन्कोड किया है, तो उसे हाथों का प्रतिनिधित्व करने के लिए 20 बिट्स की आवश्यकता होगी, जिसमें 0 से 2^20 = 1048576 की रेंज दी जाएगी, प्राइम्स का उपयोग करके उत्पादित रेंज के लगभग 1/100 वें, और पर्याप्त छोटा (हालांकि अभी भी कैश कोहेरेंसी मुद्दों का सामना करना पड़ रहा है) एक लुकअप टेबल तैयार करने के लिए।

बेशक, टेक्सास होल्डम जैसे गेम में पाए जाने वाले 7 कार्ड लेने के लिए और भी दिलचस्प संस्करण है, और उनसे 5 सर्वश्रेष्ठ कार्ड कार्ड मिल सकते हैं।

+0

एक निश्चित संख्या के साथ बाइनरी खोज को किसी भी तुलना की आवश्यकता नहीं है। यह पूरी तरह अंकगणित और bitwise संचालन के साथ किया जा सकता है जो परिणाम उत्पन्न करते हैं। यदि चरणों की संख्या (खोज करने के लिए तालिका का आकार) तय नहीं किया गया है तो आपको एक लूप/काउंटर की आवश्यकता होती है जो एक प्रति (बहुत अनुमानित) सशर्त कूद प्रति पुनरावृत्ति है, लेकिन अन्यथा एक ही अंकगणितीय दृष्टिकोण अभी भी लागू होता है। –

+0

@ आर क्या कहें? आपको वर्तमान नोड के मान को उस मान पर तुलना करना है जिसे आप प्रत्येक चरण में खोज रहे हैं। यदि आपके पास इसे अनुकूलित करने का कोई तरीका है, तो मुझे यह सुनना अच्छा लगेगा। –

+0

तुलनात्मक रूप से तुलनात्मक रूप से मेरा मतलब था तुलनात्मक परिणाम के आधार पर सशर्त कूद। यदि इसके बजाय आप प्रत्येक चरण में वर्तमान नोड को अद्यतन करने के लिए अंकगणित (साइन एक्सटेंशन का उपयोग करना) करते हैं, तो कोई कूद नहीं होता है, और यह प्रति चरण केवल कई ऑपकोड के लिए आता है। –

0

गुणा तेजी से है।

किसी दिए गए सरणी का गुणा हमेशा सरणी को सॉर्ट करने से तेज होगा, गुणात्मक परिणाम को सार्थक परिणाम में मानते हुए, और लुकअप तालिका अप्रासंगिक है क्योंकि कोड को पोकर हाथ का मूल्यांकन करने के लिए डिज़ाइन किया गया है, इसलिए आपको करना होगा वैसे भी क्रमबद्ध सेट पर एक लुकअप।

0

तैयार किए गए टेक्सास होल्डम 7- और 5-कार्ड मूल्यांकनकर्ता का एक उदाहरण here दस्तावेज़ीकरण के साथ पाया जा सकता है और here समझाया जा सकता है। सभी फीडबैक उसमें मिले ई-मेल पते पर आपका स्वागत है।

आपको 7-कार्ड हाथों का मूल्यांकन करते समय क्रमबद्ध करने की आवश्यकता नहीं है, और आमतौर पर (~ 9 7% समय) केवल 6 जोड़ों और कुछ बिट बदलावों से दूर हो सकता है। अलगो एक जेनरेट लुकअप टेबल का उपयोग करता है जो 9 एमबी रैम पर रहता है और निकट-तत्काल में उत्पन्न होता है। सस्ते। यह सब 32-बिट्स के अंदर किया जाता है, और 7-कार्ड मूल्यांकनकर्ता "इनलाइनिंग" मेरे लैपटॉप पर लगभग 50 मीटर यादृच्छिक रूप से जेनरेट किए गए हाथों का मूल्यांकन करने के लिए अच्छा है।

ओह, और गुणा सॉर्टिंग से तेज़ है।

संबंधित मुद्दे