2012-12-21 25 views
6

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

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

struct Range 
{ 
unsigned short start; 
unsigned short end; 
} 

मैं हमेशा Range की एक सरणी होगा आकार 2^n। जबकि मैं थ्रेसहोल्ड पर कुछ ढूंढता हूं, मुझे यकीन है कि यह बस तेज़ होगा या यह सब एक साथ होगा और अंत में जांच करेगा ... मान लीजिए कि मैं लूप को सदिश कर सकता हूं। हालांकि अगर मैं प्रत्येक वेक्टर के परिणामों के खंड पर एक बयान कर सकता हूं, तो यह भव्य होगा।

size_t rangecount = 1 << resolution; 
Range* ranges = new Range[rangecount]; 

... 

bool result = false; 
for (size_t i = 0; i < ranges; ++i) 
{ 
result |= (range[i].end - range[i].start) > 4; 
} 

नहीं आश्चर्यजनक रूप से, ऑटो vectorizer 1202 त्रुटि देता है क्योंकि मेरे डेटा प्रकार नहीं 32 या 64 बिट्स चौड़ा है। मैं वास्तव में अपने डेटा आकार को दोगुना नहीं करना चाहता हूं और प्रत्येक फ़ील्ड को एक हस्ताक्षरित int बनाना चाहता हूं। तो मैं अनुमान लगा रहा हूं कि ऑटो-वेक्टरिज़र दृष्टिकोण इसके लिए बाहर है।

क्या वेक्टर निर्देश हैं जो 16 बिट चर को संभाल सकते हैं? यदि वहां हैं, तो मैं अपने लूप को सदिश बनाने के लिए C++ में उनका उपयोग कैसे कर सकता हूं?

+0

आप एक सरणी में सीमा मान संग्रहीत की जरूरत है? उन्हें अन्य डेटा संरचना में क्यों स्टोर न करें जो इस लुकअप को तेज़ कर देगा? – loganfsmyth

+0

_so यह ट्रैक करना संभव नहीं है कि कौन सी रेंज ऑब्जेक्ट्स सूची या कुछ_ में थ्रेसहोल्ड से ऊपर हैं। यदि आप बस इतना करना चाहते हैं कि यह निर्धारित करता है कि आपके पास नियम हैं जो नियम तोड़ते हैं, तो उसे ट्रैक करें। ऐसा करने के लिए आपको हर ऑब्जेक्ट को ट्रैक करने की आवश्यकता नहीं है। –

+0

आप कितनी बार 'एंड' का उपयोग करते हैं? '(प्रारंभ, अंत)' के बजाय '(प्रारंभ, आकार) 'प्रतिनिधित्व पर स्विच करना संभव होगा। निश्चित रूप से आपको हर बार 'एंड' की गणना करने की आवश्यकता होगी, लेकिन अगर 'एंड' बनाम' आकार का सापेक्ष उपयोग कम है, तो यह अभी भी जीत के अंत में समाप्त हो सकता है ... – twalberg

उत्तर

1

आप सोच रहे हैं कि कोई मान 4 से अधिक है?

हां, इसके लिए सिम निर्देश हैं। यह दुर्भाग्यपूर्ण है कि ऑटो-वेक्टरिज्ड इस परिदृश्य को संभालने में सक्षम नहीं है।

diff_v = end_v - start_v; // _mm_hsub_epi16 
floor_v = max(4_v, diff_v); // _mm_max_epi16 
if (floor_v != 4_v) return true; // wide scalar comparison 

उपयोग _mm_sub_epi16 सरणियों की एक संरचना या _mm_hsub_epi16 संरचनाओं की एक सरणी के साथ साथ: यहाँ एक vectorized एल्गोरिथ्म है।

start के बाद से

वास्तव में स्मृति में पहली संग्रहीत किया जाता है, तो आप start_v - end_v पर काम किया जाएगा, ताकि _mm_min_epi16 का उपयोग करें और -4 का एक वेक्टर।

प्रत्येक SSE3 अनुदेश एक समय में 8 तुलना प्रदर्शन करेंगे। यह अभी भी लूपिंग के बजाय जल्दी लौटने के लिए सबसे तेज़ होगा। हालांकि, लूप को अनलॉक करने से थोड़ा अधिक आपको अतिरिक्त गति मिल सकती है (पैक किए गए न्यूनतम/अधिकतम फ़ंक्शन में परिणामों को जोड़ने के लिए उन्हें सेट करें)।

तो आप के साथ (लगभग) अंत:

most_negative = threshold = _mm_set_epi64(0xFCFCFCFCFCFCFCFC); // vectorized -4 

loop: 
    a = load from range; 
    b = load from range; 
    diff = _mm_hsub_epi16(a, b); 
    most_negative = _mm_min_epi16(most_negative, diff); 

    // unroll by repeating the above four instructions 4 times or so 
    if (most_negative != threshold) return true; 
repeat loop 
+0

ऑटो-वेक्टरिज़र कुछ नहीं कर सकता है, यह सुनिश्चित करना आसान लगता है! – user173342

+0

@ user173342: बिल्कुल दो सदस्यों के साथ इंटरलीव किए गए सरणी से निपटना एक विशेष मामला है, और एक ऐसा है कि ऑटो-वेक्टरिज़र शायद तैयार नहीं है। –