जितनी जल्दी हो सके पाँच छोटे पूर्णांकों में से दो को खोजना


9

मैं एक छोटे एम्बेडेड सिस्टम पर छवि डेटा पर 5-क्रॉस माध्य फ़िल्टर की भिन्नता का उपयोग करता हूं, अर्थात

    x
  x x x
    x

एल्गोरिथ्म वास्तव में सरल है: 5 अहस्ताक्षरित पूर्णांक मान पढ़ें, उच्चतम 2 प्राप्त करें, उन पर कुछ गणना करें और अहस्ताक्षरित पूर्णांक परिणाम लिखें।

क्या अच्छा है कि 5 पूर्णांक इनपुट मान सभी 0-20 की सीमा में हैं। परिकलित पूर्णांक मान 0-20 श्रेणी में भी हैं!

प्रोफाइलिंग के माध्यम से, मुझे पता चला है कि सबसे बड़ी दो संख्याओं को प्राप्त करना अड़चन है, इसलिए मैं इस भाग को गति देना चाहता हूं। इस चयन को करने का सबसे तेज़ तरीका क्या है?

वर्तमान एल्गोरिथ्म 5 संख्याओं और एक HW- समर्थित CLZ फ़ंक्शन द्वारा दी गई स्थिति में 1 के साथ 32 बिट मास्क का उपयोग करता है।
मुझे कहना चाहिए कि सीपीयू एक मालिकाना है, मेरी कंपनी के बाहर उपलब्ध नहीं है। मेरा संकलक GCC है लेकिन इस CPU के लिए दर्जी।

मैंने यह पता लगाने की कोशिश की है कि क्या मैं लुकअप-टेबल का उपयोग कर सकता हूं लेकिन मैं एक कुंजी उत्पन्न करने में विफल रहा हूं जिसका मैं उपयोग कर सकता हूं।

मेरे पास है 215इनपुट के लिए संयोजन लेकिन आदेश महत्वपूर्ण नहीं है, अर्थात [5,0,0,0,5]जैसा है वैसा ही है [5,5,0,0,0]

ऐसा होता है कि नीचे हैश-फ़ंक्शन टकराव के बिना एक आदर्श हैश का उत्पादन करता है!

def hash(x):
    h = 0
    for i in x:
        h = 33*h+i
    return h

लेकिन हैश बहुत बड़ा है और इसका उपयोग करने के लिए पर्याप्त मेमोरी नहीं है।

क्या एक बेहतर एल्गोरिथ्म है जिसका मैं उपयोग कर सकता हूं? क्या लुकअप-टेबल का उपयोग करके और एक कुंजी उत्पन्न करके मेरी समस्या को हल करना संभव है?


1
वर्तमान में आप किस एल्गोरिथ्म का उपयोग करते हैं? सात पूर्णांक तुलना काफी हैं, क्या यह बहुत धीमी है? आपका hashपहले से ही अधिक संचालन करता है। संबंधित कॉल के लिए बाद में कॉल कर रहे हैं, जैसे केंद्रीय xमैट्रिक्स पंक्ति-दर-पंक्ति के माध्यम से चलता है?
राफेल

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

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

@jkff मैट्रिक्स, कैश आकार और (कैश) मैपिंग फ़ंक्शन के आधार पर, हर मूल्य को केवल एक बार लोड करना पड़ सकता है; अधिकांश ऑपरेशन रजिस्टरों या L1 कैश पर चलने चाहिए। हालांकि, पाइपलाइनिंग एक और मुद्दा है।
राफेल

1
वैसे, क्या आप पहले से ही समानांतर में ऐसा करते हैं? यह विशेष रूप से वेक्टर समांतरकरण या SIMD (उदाहरण के लिए GPU पर) के लिए उपयुक्त लगता है। यह मार्ग प्रति सेल कुछ प्रतिशत बचाने में बहुत अधिक मदद करेगा।
राफेल

जवाबों:


11

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

बेशक, छँटाई बहुत काम हो सकती है; हमें केवल सबसे बड़ी दो संख्याओं की आवश्यकता है। हमारे लिए भाग्यशाली, चयन नेटवर्क का भी अध्ययन किया गया है। नुथ हमें बताता है कि पांच be में से दो सबसे छोटी संख्याओं को खोजने के साथ किया जा सकता है यू^2(5)=6 तुलना [१, ५.३.४ पूर्व १ ९] (और अधिक से अधिक स्वैप)।

नेटवर्क वह समाधानों में देता है (शून्य-आधारित सरणियों को फिर से लिखा गया है)

[0:4][1:4][0:3][1:3][0:2][1:2]

जो लागू होता है - तुलना की दिशा को समायोजित करने के बाद - छद्मकोश में के रूप में

def selMax2(a : int[])
  a.swap(0,4) if a[0] < a[4]
  a.swap(1,4) if a[1] < a[4]
  a.swap(0,3) if a[0] < a[3]
  a.swap(1,3) if a[1] < a[3]
  a.swap(0,2) if a[0] < a[2]
  a.swap(1,2) if a[1] < a[2]
  return (a[0], a[1])
end

अब, भोले क्रियान्वयन में अभी भी सशर्त कूदता है (स्वैप कोड के पार)। हालाँकि, आपकी मशीन के आधार पर आप उन्हें सशर्त निर्देशों के साथ सक्रिय कर सकते हैं। x86 अपने सामान्य मैडपिट स्वयं प्रतीत होता है; एआरएम अधिक आशाजनक लग रहा है क्योंकि स्पष्ट रूप से अधिकांश ऑपरेशन अपने आप में सशर्त हैं। तो मैं समझता हूँ निर्देश को सही ढंग से, पहले स्वैप इस के लिए अनुवाद, यह मानते हुए हमारे सरणी मूल्यों रजिस्टर करने के लिए लोड हो जाने R0के माध्यम से R4:

CMP     R0,R4
MOVLT   R5 = R0
MOVLT   R0 = R4
MOVLT   R4 = R6

हां, हां, निश्चित रूप से आप EOR के साथ XOR स्वैपिंग का उपयोग कर सकते हैं ।

मुझे उम्मीद है कि आपके प्रोसेसर में यह या ऐसा ही कुछ है। बेशक, यदि आप इस उद्देश्य के लिए चीज का निर्माण करते हैं , तो शायद आप नेटवर्क को वहां पर हार्ड-वायर्ड प्राप्त कर सकते हैं?

यह संभवतः (सिद्ध रूप से?) सबसे अच्छा आप शास्त्रीय क्षेत्र में कर सकते हैं, अर्थात सीमित डोमेन का उपयोग किए बिना और दुष्ट इंट्रा-वर्ड मैजिक का प्रदर्शन करना।


  1. डोनाल्ड ई। नुथ द्वारा क्रमबद्ध और खोज ; कंप्यूटर प्रोग्रामिंग वॉल्यूम की कला । 3 (दूसरा संस्करण, 1998)
  2. ध्यान दें कि यह दो चयनित तत्वों को अव्यवस्थित छोड़ देता है। उन्हें ऑर्डर करने के लिए एक अतिरिक्त तुलना की आवश्यकता होती है, वह हैडब्ल्यू^2(5)=7 कुल में कई [1, p234 तालिका 1]।

मैं इसे स्वीकार कर रहा हूं। मुझे बहुत सारे नए विचार मिले जिन्हें आगे बढ़ने से पहले मुझे बेंचमार्क करने की आवश्यकता है। नुथ का जिक्र हमेशा मेरे लिए काम करता है :-) आपके प्रयास और समय के लिए धन्यवाद!
फ्रेड्रिक पिहल

@FredrikPihl कूल, कृपया हमें बताएं कि यह अंत में कैसे बदल जाता है!
राफेल

मे लूँगा! अध्याय 5.3.3 अभी पढ़ना। लुईस कैरोल और टेनिस टूर्नामेंट :-) के संदर्भ में इसे शुरू करने से प्यार करें
फ्रेड्रिक पिहल

2
निर्देश सेट के आधार पर, 2 * अधिकतम (a, b) = a + b + abs (ab) के साथ-साथ चयन नेटवर्क का उपयोग उपयोगी हो सकता है; यह अप्रत्याशित सशर्त जंपर्स की तुलना में कम महंगा हो सकता है (यहां तक ​​कि पेट के लिए एक आंतरिक या सशर्त चाल के बिना भी: gcc, कम से कम x86 के लिए, एक jumeless अनुक्रम उत्पन्न करता है जो x86 पर निर्भर नहीं लगता है)। SIMD या GPU के साथ संयुक्त होने पर जंपलेस अनुक्रम भी उपयोगी है।
एपीग्रामग्राम

1
ध्यान दें कि चयन नेटवर्क (जैसे सॉर्टिंग नेटवर्क) समानांतर संचालन के लिए उत्तरदायी हैं; निर्दिष्ट नेटवर्क में विशेष रूप से, तुलना 1: 4 और 0: 3 समानांतर में किया जा सकता है (यदि प्रोसेसर, कंपाइलर, आदि जो कुशलता से समर्थन करते हैं), और 1: 3 और 0: 2 की तुलना समानांतर में भी की जा सकती है।
ब्रूस लिली

4

बस इतना है कि यह मेज पर है, यहाँ एक सीधा एल्गोरिदम है:

// Sort x1, x2
if x1 < x2
  M1 = x2
  m1 = x1
else
  M1 = x1
  m1 = x2
end

// Sort x3, x4
if x3 < x4
  M2 = x4
  m2 = x3
else
  M2 = x3
  m2 = x4
end

// Pick largest two
if M1 > M2
  M3 = M1
  if m1 > M2
    m3 = m1
  else
    m3 = M2
  end
else
  M3 = M2
  if m2 > M1
    m3 = m2
  else
    m3 = M1
  end
end

// Insert x4
if x4 > M3
  m3 = M3
  M3 = x4
else if x4 > m3
  m3 = x4
end

के चतुर कार्यान्वयन से if ... else, कुछ बिना शर्त कूद से छुटकारा पा सकता है जिसका सीधा अनुवाद होगा।

यह बदसूरत है, लेकिन केवल लेता है

  • पांच या छह तुलना (यानी सशर्त छलांग),
  • नौ से दस असाइनमेंट (11 चर के साथ, सभी रजिस्टरों में) और
  • अतिरिक्त मेमोरी एक्सेस नहीं है।

वास्तव में, छह तुलनाएं इस समस्या के लिए इष्टतम हैं क्योंकि [1] शो के धारा ५.३.३ में प्रमेय एस; यहाँ हमें जरूरत हैडब्ल्यू2(5)

हालांकि, पाइपलाइनिंग के साथ मशीनों पर तेजी से होने की उम्मीद नहीं की जा सकती है; उन्हें सशर्त कूद का उच्च प्रतिशत दिया जाता है, ज्यादातर समय संभवतः स्टाल में बिताया जाएगा।

ध्यान दें कि एक सरल प्रकार - सॉर्ट x1और x2, उसके बाद अन्य मान डालें - चार से सात तुलना और केवल पांच से छह असाइनमेंट लेता है। चूंकि मैं उम्मीद करता हूं कि यहां ऊंची लागत की छलांग लगेगी, इसलिए मैं इस पर टिक गया।


  1. डोनाल्ड ई। नुथ द्वारा क्रमबद्ध और खोज ; कंप्यूटर प्रोग्रामिंग वॉल्यूम की कला । 3 (दूसरा संस्करण, 1998)

मुझे आश्चर्य है कि एक अनुकूलन करने वाला कंपाइलर इनसे क्या कर सकता है।
राफेल

मैं इसे लागू करूंगा और इसे वर्तमान सीएलजेड-आधारित समाधान के खिलाफ बेंचमार्क करूंगा। आपके समय के लिए धन्यवाद!
फ्रेड्रिक पिहल

1
@FredrikPihl आपके बेंचमार्क का परिणाम क्या था?
राफेल

1
स्वैप आधारित दृष्टिकोण CLZ धड़कता है! मोबाइल पर अब मोबाइल पर अब एक और डेटा पोस्ट कर सकते हैं
फ्रेड्रिक पिहल

@FredrikPihl कूल! मुझे खुशी है कि अच्छे पुराने सिद्धांत दृष्टिकोण (अभी भी) व्यावहारिक उपयोग के हो सकते हैं। :)
राफेल

4

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

सूप खुला स्रोत है। आप अपने कोड स्निपेट पर सूप को चलाने की कोशिश कर सकते हैं, यह देखने के लिए कि क्या यह कोई बेहतर कर सकता है।

16 4-बिट मानों को सॉर्ट करने के लिए फास्ट कोड लिखने पर जॉन रेगर की प्रतियोगिता भी देखें ; यह संभव है कि वहां की कुछ तकनीकें उपयोगी हो सकती हैं।


मैं उन कार्यक्रमों में दिलचस्पी ले सकता हूं जो ओपी की कोशिशों पर आधारित हैं।
राफेल

3

आप एक का उपयोग कर सकते हैं 213तालिका जो तीन पूर्णांकों को प्राप्त करती है और सबसे बड़े दो को आउटपुट करती है। फिर आप तीन टेबल लुकअप का उपयोग कर सकते हैं:

T[T[T[441*a+21*b+c]*21+d]*21+e]

इसी तरह, एक का उपयोग कर 214 तालिका, आप इसे दो तालिका लुकअप में कम कर सकते हैं, हालांकि यह स्पष्ट नहीं है कि यह तेजी से होगा।

यदि आप वास्तव में एक छोटी सी तालिका चाहते हैं, तो आप दो का उपयोग कर सकते हैं 212तालिकाओं को "दो" क्रमबद्ध करने के लिए, और फिर एक छँटाई नेटवर्क का उपयोग करें। विकिपीडिया के अनुसार , इसके लिए अधिकतम 18 टेबल लुकअप (9 तुलनित्र) की आवश्यकता होती है; आप कम से कम करने में सक्षम हो सकते हैं (1) आप केवल दो सबसे बड़े तत्वों को जानना चाहते हैं, और (2) कुछ तुलनित्र फाटकों के लिए, आप केवल अधिकतम में दिलचस्पी ले सकते हैं।

आप सिंगल का भी इस्तेमाल कर सकते हैं 212तालिका। एक सॉर्टिंग नेटवर्क को लागू करना तब कम मेमोरी एक्सेस का उपयोग करता है लेकिन अधिक अंकगणित। इस तरह आपको ज्यादातर 9 टेबल लुकअप मिलते हैं।

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