2009-03-20 15 views
9

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

ऐसा करने का सबसे प्रभावी तरीका क्या है?

आपके उत्तरों के लिए धन्यवाद।

उत्तर

13
for (i = 10 ; i-- > 0 ;) 
    result_array[i] = byte_array[i] & byte_mask[i]; 
  • जा रहे हैं पीछे की ओर पहले से लोड कर प्रोसेसर कैश लाइनों।
  • तुलना में कमी सहित कुछ निर्देशों को बचा सकता है।

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

उदाहरण के लिए, n=16n=10 के बजाय कहें। फिर इस बहुत तेजी से होगा:

uint32_t* input32 = (uint32_t*)byte_array; 
uint32_t* mask32 = (uint32_t*)byte_mask; 
uint32_t* result32 = (uint32_t*)result_array; 
for (i = 4 ; i-- > 0 ;) 
    result32[i] = input32[i] & mask32[i]; 

(बेशक आप uint32_t के लिए एक उचित प्रकार की जरूरत है, और अगर n 2 के एक शक्ति आप शुरू और/या समाप्त होने को साफ करने की जरूरत नहीं है, इसलिए है कि 32- बिट सामान गठबंधन है।)

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

+0

रुको, क्या कैश प्रीफ़ेचर रिवर्स में बेहतर काम करता है? मैंने सोचा कि यह केवल आगे बढ़ने के लिए prefetched। – Crashworks

+2

प्री-लोडिंग प्रोसेसर कैश-लाइनों के बारे में चिंता करना गंभीर समयपूर्व अनुकूलन की तरह लगता है। – Trent

+5

@ ट्रेंट - प्रश्न का * बिंदु * अनुकूलन है। पीछे की ओर भी धीमा नहीं है, तो आप भी हो सकते हैं। @ क्रैशवर्क्स - याद रखें कि कैश लाइनों को गठबंधन किया जाता है, आमतौर पर भारी सीमाओं पर, इसलिए आमतौर पर इसे उन लोगों से पहले बाइट्स में खींचना पड़ता है जिन्हें आप पूछ रहे हैं। –

5

आप यह तेजी से बनाना चाहते हैं, तो सुनिश्चित करें byte_array लंबाई है कि 4 के कई है (8 64-बिट मशीनों पर) है, और फिर:

char byte_array[12]; 
char byte_mask[12]; 
/* Checks for proper alignment */ 
assert(((unsigned int)(void *)byte_array) & 3 == 0); 
assert(((unsigned int)(void *)byte_mask) & 3 == 0); 
for (i = 0; i < (10+3)/4; i++) { 
    ((unsigned int *)(byte_array))[i] &= ((unsigned int *)(byte_mask))[i]; 
} 

यह बाइट की तुलना में बहुत तेजी से होता है प्रति बाइट

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

+0

10/4 == 2, इसलिए यह केवल 8 वर्णों को संसाधित करता है। इसके अलावा, कुछ गैर-x86 आर्किटेक्चर पर यह असाइन किए गए मेमोरी एक्सेस के कारण बस त्रुटि उत्पन्न कर सकता है। – bk1e

+0

bk1e: आप सही हैं, मैं <10/4 गलत है। बस त्रुटि के बारे में टिप्पणी भी सही है। मैं जवाब संपादित कर दूंगा। –

+0

यदि यह 4/8 का एकाधिक नहीं है, तो डफ के डिवाइस का उपयोग करें :) – Brian

1
\#define CHAR_ARRAY_SIZE (10) 
\#define INT_ARRAY_SIZE  ((CHAR_ARRAY_SIZE/ (sizeof (unsigned int)) + 1) 

typedef union _arr_tag_ { 

    char   byte_array [CHAR_ARRAY_SIZE]; 
    unsigned int int_array [INT_ARRAY_SIZE]; 

} arr_tag; 

अब मास्किंग के लिए int_array। यह 32 बिट और 64 बिट प्रोसेसर दोनों के लिए काम कर सकता है।

arr_tag arr_src, arr_result, arr_mask; 

for (int i = 0; i < INT_ARRAY_SIZE; i ++) { 
    arr_result.int_array [i] = arr_src.int_array[i] & arr_mask.int_array [i]; 
} 

इस प्रयास करें, कोड भी साफ लग सकता है।

+0

उदाहरण कोड लिखने के लिए धन्यवाद :) – alvatar

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