दिलचस्प पोस्ट
स्टार्टअप पर एंड्रॉइड ब्रॉडकास्ट रिसीवर – गतिविधि पृष्ठभूमि में है जब चलते रहें NSFetchedResultsController के साथ predicate विभिन्न NSManagedObjectContext से विलय परिवर्तनों की उपेक्षा क्यों "int uint == सच है" सी # में नई फ़ाइलों के लिए एंड्रॉइड एसडी कार्ड स्कैन करें कन्स्ट्रक्टर एक अशक्त वस्तु वापस कर सकता है? स्ट्रिंग के अंतिम भाग को बदलें एक फ़ाइल में डुप्लिकेट लाइनें ढूंढें और गणना करें कि प्रत्येक पंक्ति को कितनी बार डुप्लिकेट किया गया था? इन दो बार (1 9 27 में) एक अजीब परिणाम देकर क्यों घटाना है? HTML प्रपत्र में टेक्स्ट पेस्ट करना अक्षम करें मेमोरी-कुशल तरीके से डेटा.फ्रेम बढ़ाना सी # में कस्टम भाषा सुविधाओं को लागू करने का कोई तरीका है? एक्स "x = x ++" के बाद क्या है? कैसे ऐनम मूल्य के लिए कोशिश करो? तुलना की न्यूनतम संख्या के साथ एक सरणी क्रमबद्ध करें विंडोज पर भरोसेमंद file.renameTo () विकल्प?

डफ के उपकरण कैसे काम करता है?

मैंने डफ़ के उपकरण पर विकिपीडिया पर लेख पढ़ा है , और मुझे यह नहीं मिलता। मैं वास्तव में दिलचस्पी है, लेकिन मैंने कई बार स्पष्टीकरण पढ़ लिया है और मैं अभी भी यह नहीं जानता कि कैसे डफ़ के उपकरण काम करता है।

अधिक विस्तृत व्याख्या क्या होगी?

वेब के समाधान से एकत्रित समाधान "डफ के उपकरण कैसे काम करता है?"

वहां कुछ अच्छी व्याख्याएं हैं, लेकिन मुझे इसे एक कोशिश दें (यह व्हाइटबोर्ड पर बहुत आसान है!) यहां कुछ नोटों के साथ विकिपीडिया का उदाहरण है।

मान लें कि आप 20 बाइट्स कॉपी कर रहे हैं पहला पास के लिए प्रोग्राम का प्रवाह नियंत्रण है:

int count; // Set to 20 { int n = (count + 7) / 8; // n is now 3. (The "while" is going // to be run three times.) switch (count % 8) { // The remainder is 4 (20 modulo 8) so // jump to the case 4 case 0: // [skipped] do { // [skipped] *to = *from++; // [skipped] case 7: *to = *from++; // [skipped] case 6: *to = *from++; // [skipped] case 5: *to = *from++; // [skipped] case 4: *to = *from++; // Start here. Copy 1 byte (total 1) case 3: *to = *from++; // Copy 1 byte (total 2) case 2: *to = *from++; // Copy 1 byte (total 3) case 1: *to = *from++; // Copy 1 byte (total 4) } while (--n > 0); // N = 3 Reduce N by 1, then jump up // to the "do" if it's still } // greater than 0 (and it is) } 

अब, दूसरा पास शुरू करें, हम सिर्फ संकेत कोड चलाते हैं:

 int count; // { int n = (count + 7) / 8; // // switch (count % 8) { // // case 0: // do { // The while jumps to here. *to = *from++; // Copy 1 byte (total 5) case 7: *to = *from++; // Copy 1 byte (total 6) case 6: *to = *from++; // Copy 1 byte (total 7) case 5: *to = *from++; // Copy 1 byte (total 8) case 4: *to = *from++; // Copy 1 byte (total 9) case 3: *to = *from++; // Copy 1 byte (total 10) case 2: *to = *from++; // Copy 1 byte (total 11) case 1: *to = *from++; // Copy 1 byte (total 12) } while (--n > 0); // N = 2 Reduce N by 1, then jump up // to the "do" if it's still } // greater than 0 (and it is) } 

अब, तीसरे पास शुरू करें:

 int count; // { int n = (count + 7) / 8; // // switch (count % 8) { // // case 0: // do { // The while jumps to here. *to = *from++; // Copy 1 byte (total 13) case 7: *to = *from++; // Copy 1 byte (total 14) case 6: *to = *from++; // Copy 1 byte (total 15) case 5: *to = *from++; // Copy 1 byte (total 16) case 4: *to = *from++; // Copy 1 byte (total 17) case 3: *to = *from++; // Copy 1 byte (total 18) case 2: *to = *from++; // Copy 1 byte (total 19) case 1: *to = *from++; // Copy 1 byte (total 20) } while (--n > 0); // N = 1 Reduce N by 1, then jump up // to the "do" if it's still } // greater than 0 (and it's not, so bail) } // continue here... 

20 बाइट्स अब कॉपी किए गए हैं

नोट: मूल डफ़ के डिवाइस (ऊपर दिखाए गए) पते पर एक I / O डिवाइस पर प्रतिलिपि की गई। इस प्रकार, सूचक को *to बढ़ाने के लिए आवश्यक नहीं था दो स्मृति बफ़र्स के बीच नकल करते समय आपको *to++ का उपयोग करने की आवश्यकता होती है

डॉ। डॉब के जर्नल में स्पष्टीकरण सबसे अच्छा विषय है जिस पर मुझे मिला।

यह मेरा अहा क्षण रहा है:

 for (i = 0; i < len; ++i) { HAL_IO_PORT = *pSource++; } 

हो जाता है:

 int n = len / 8; for (i = 0; i < n; ++i) { HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; HAL_IO_PORT = *pSource++; } 

🙂 बन जाता है:

 int n = (len + 8 - 1) / 8; switch (len % 8) { case 0: do { HAL_IO_PORT = *pSource++; case 7: HAL_IO_PORT = *pSource++; case 6: HAL_IO_PORT = *pSource++; case 5: HAL_IO_PORT = *pSource++; case 4: HAL_IO_PORT = *pSource++; case 3: HAL_IO_PORT = *pSource++; case 2: HAL_IO_PORT = *pSource++; case 1: HAL_IO_PORT = *pSource++; } while (--n > 0); } 

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

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

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

डफ डिवाइस का मतलब तंग मेम्क्की कार्यान्वयन में किए गए तुलना की संख्या को कम करना है।

मान लीजिए कि आप 'गिनती' बाइट्स को एक से बी की प्रतिलिपि बनाना चाहते हैं, तो सीधे आगे की दिशा निम्नलिखित करना है:

  do { *a = *b++; } while (--count > 0); 

यह देखने के लिए कितनी बार आपको गिनती की तुलना करने की आवश्यकता है कि क्या यह ऊपर 0 है? 'गणना' बार

अब, डफ डिवाइस एक स्विच मामले के एक गंदा अनियंत्रित दुष्प्रभाव का उपयोग करता है जो आपको / 8 की गिनती करने के लिए आवश्यक तुलना की संख्या को कम करने की अनुमति देता है।

अब मान लें कि आप डफ़्स डिवाइस का उपयोग करके 20 बाइट कॉपी करना चाहते हैं, आपको कितनी तुलना की आवश्यकता होगी? केवल 3, जब आप पिछली पहली बार को छोड़कर एक समय में आठ बाइट कॉपी करते हैं, जहां आप केवल 4 की प्रतिलिपि करते हैं।

नवीनीकृत: आपको 8 तुलना / केस-इन-स्विच स्टेटमेंट्स करने की ज़रूरत नहीं है, लेकिन यह फ़ंक्शन आकार और गति के बीच एक ट्रेड-ऑफ उचित है

जब मैंने इसे पहली बार पढ़ा, तो मैंने इसे इस पर स्वत: स्वरूपित किया

 void dsend(char* to, char* from, count) { int n = (count + 7) / 8; switch (count % 8) { case 0: do { *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0); } } 

और मुझे नहीं पता था कि क्या हो रहा था।

हो सकता है कि जब यह प्रश्न पूछा न हो, लेकिन अब विकिपीडिया का बहुत अच्छा विवरण है

डिवाइस वैध है, सी में दो विशेषताओं के आधार पर कानूनी सी:

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

1: डफ़्स डिवाइस लूप अनोलोलिंग का एक विशेष रूप से फांलापन है। पाश अनारोलिंग क्या है?
यदि आपके पास लूप में एन बार करने के लिए कोई ऑपरेशन होता है, तो आप लूप एन / एन बार निष्पादित करके और तब लूप में एनिलिंग (अनोलोलिंग) लूप कोड n बार जैसे स्थान के लिए गति के लिए प्रोग्राम आकार व्यापार कर सकते हैं।

 for (int i=0; i<N; i++) { // [The loop code...] } 

साथ में

 for (int i=0; i<N/n; i++) { // [The loop code...] // [The loop code...] // [The loop code...] ... // [The loop code...] // n times! } 

जो अच्छा काम करता है अगर एन% एन == 0 – डफ की कोई ज़रूरत नहीं है! अगर यह सच नहीं है तो आपको शेष को संभालना होगा – यह एक दर्द है।

2: डफ डिवाइस इस मानक पाश को अनारोल्ड से कैसे अलग करता है?
डफ डिवाइस केवल शेष लूप चक्र से निपटने का एक चतुर तरीका है, जब एन% एन! = 0। संपूर्ण लूप निरंतर के अनुसार एन / एन की संख्या पूरी करते / करते हैं (क्योंकि मामला लागू होता है)। लूप ('N / n + 1'th समय) के माध्यम से आखिरी रन में, मामले में किक और हम एन% एन केस से कूदते हैं और लूप कोड' शेष 'की संख्या को चलाते हैं।

यद्यपि मैं 100% निश्चित नहीं हूँ कि आप क्या पूछ रहे हैं, यहां जाता है …

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

एक वैकल्पिक उदाहरण के रूप में, जो इसे समझना आसान बना सकता है, कल्पना करें कि आपके पास आइटम की एक सरणी है जिसे आप लूप करना चाहते हैं, और प्रत्येक बार 1 उन्हें जोड़ें … सामान्यतः, आप लूप के लिए, और लगभग 100 बार लूप का उपयोग कर सकते हैं । यह काफी तार्किक लगता है और, यह है … हालांकि, एक ऑप्टिमाइज़ेशन पाश को खोलने के द्वारा किया जा सकता है (स्पष्ट रूप से बहुत दूर नहीं है … या आप भी लूप का उपयोग नहीं कर सकते हैं)।

तो एक नियमित लूप के लिए:

 for(int i = 0; i < 100; i++) { myArray[i] += 1; } 

हो जाता है

 for(int i = 0; i < 100; i+10) { myArray[i] += 1; myArray[i+1] += 1; myArray[i+2] += 1; myArray[i+3] += 1; myArray[i+4] += 1; myArray[i+5] += 1; myArray[i+6] += 1; myArray[i+7] += 1; myArray[i+8] += 1; myArray[i+9] += 1; } 

डफ के उपकरण क्या करता है, इस विचार को सी में लागू होता है, लेकिन (जैसा कि आप विकी पर देखा था) सीरियल प्रतियों के साथ जो ऊपर आप देख रहे हैं, अवांछित उदाहरण के साथ, 10 तुलना की तुलना में मूल में 100 – यह एक छोटी सी, लेकिन संभवतः महत्वपूर्ण, अनुकूलन के बराबर है

यहाँ एक गैर-विस्तृत व्याख्या है, जो मुझे डफ़ के उपकरण की जड़ होने का अनुभव करती है:

बात यह है कि, सी मूल रूप से विधानसभा भाषा (पीडीपी -7 विधानसभा को विशिष्ट होने के लिए एक अच्छा मुखौटा है; यदि आप पढ़ते हैं कि आप देखेंगे कि समानताएं कैसे हड़ताएं) और, विधानसभा भाषा में, आपके पास वास्तव में छोर नहीं हैं – आपके पास लेबल और सशर्त-शाखा निर्देश हैं इसलिए लूप केवल एक लेबल और एक शाखा के साथ निर्देशों के समग्र अनुक्रम का एक हिस्सा है:

  instruction label1: instruction instruction instruction instruction jump to label1 some condition 

और एक स्विच अनुदेश आगे बंट रहा है / कुछ हद तक कूदता है:

  evaluate expression into register r compare r with first case value branch to first case label if equal compare r with second case value branch to second case label if equal etc.... first_case_label: instruction instruction second_case_label: instruction instruction etc... 

विधानसभा में यह आसानी से बोधगम्य है कि इन दो नियंत्रण संरचनाओं को कैसे संयोजित किया जाए, और जब आप इसके बारे में सोचते हैं, तो सी में उनका संयोजन इतना अजीब नहीं लगता है।

बस प्रयोग, स्विच और पाश को बिना किसी अंतर के साथ मिलते हुए एक अन्य संस्करण मिला:

 int n = (count + 1) / 8; switch (count % 8) { LOOP: case 0: if(n-- == 0) break; putchar('.'); case 7: putchar('.'); case 6: putchar('.'); case 5: putchar('.'); case 4: putchar('.'); case 3: putchar('.'); case 2: putchar('.'); case 1: putchar('.'); default: goto LOOP; }