सी

2012-12-07 30 views
5

में एकरमेन फ़ंक्शन का वैकल्पिक कार्यान्वयन मैंने सी में एक प्रोग्राम लिखा था जो उपयोगकर्ता द्वारा दर्ज 2 गैर-नकारात्मक पूर्णांक के लिए एकरमेन मानों की गणना करता है। कार्यक्रम जांचता है कि क्या पूर्णांक गैर-ऋणात्मक हैं और यदि वे हैं तो यह उनके एकरमेन मूल्य की गणना करता है और फिर नए इनपुट या बाहर निकलने के लिए कहता है। कार्यक्रम सी में ठीक काम करता है और मुझे इसके साथ कोई समस्या नहीं है। एक विश्वविद्यालय सबक हम सी का एक संशोधित संस्करण (मूल रूप से एक ही है, लेकिन कुछ अलग सिंटैक्स नियमों के साथ) का उपयोग जो वाक्य रचना simulates की जरूरतों और के नियमों के लिए वास्तव मेंसी

int ackermann(int m, int n){ 
     if (m == 0) return n + 1; 
     if (n == 0) return ackermann(m - 1, 1); 
     return ackermann(m - 1, ackermann(m, n - 1)); 
} 

लेकिन,,: यहाँ मेरी कोड है एमआईपीएस असेंबली भाषा। अधिक विशेष रूप से, हम सरणी और structs को छोड़कर सभी डेटा में हेरफेर करने के लिए रजिस्टरों का उपयोग करते हैं। इसके अलावा, हम loops के दौरान, जबकि, या करते समय उपयोग नहीं कर सकते हैं और का उपयोग करते हैं तो और गोटो बयान के बजाय। इसलिए मैंने इस भाषा में निम्नलिखित कार्यक्रम लिखा (जैसा कि मैंने कहा है कि यह विभिन्न वाक्यविन्यास के साथ सी से अधिक नहीं है)। मेरी समस्या यह है कि यह केवल (x, 0) और (0, y) उपयोगकर्ता इनपुट (x और y गैर-ऋणात्मक संख्याओं के लिए) के लिए काम करता है। यह (4,1), (3,2) और आम तौर पर सभी इनपुट जिनमें शून्य नहीं है, के लिए काम नहीं करता है। मैं समझता हूं कि इन गणनाओं के विशाल ढेर के कारण यह बहुत बड़ी संख्या (10,10) के लिए कुशलता से काम नहीं कर सकता है। लेकिन मैं इसे एकरमैन समारोह पर एकरमैन (3,1) == 13. जैसे कुछ सरल आदानों के लिए काम करने के लिए और अधिक के लिए कृपया इस देखना चाहते हैं: http://en.wikipedia.org/wiki/Ackermann_function यहाँ मेरी कोड है:

//Registers --- The basic difference from C is that we use registers to manipulate data 
int R0=0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,R16,R17,R18,R19,R20,R21, 
R22,R23,R24,R25,R26,R27,R28,R29,R30,R31; 

int ackermann(int m, int n){ 

    R4 = m; 
    R5 = n; 

    if(R4 != 0) 
     goto outer_else; 
    R6 = R5 + 1; 
    return R6; 

    outer_else: 
     if(R5 != 0) 
      goto inner_else; 
     R7 = R4 - 1; 
     R6 = ackermann(R7, 1); 
     return R6; 

     inner_else: 
      R8 = R5 - 1; 
      R9 = ackermann(R4, R8); 
      R10 = R4 - 1; 
      R6 = ackermann(R10, R9); 
      return R6; 
} 

उत्तर

6

मुझे लगता है कि आपकी समस्या यह है कि उन रजिस्टर मानों को वैश्विक चर के रूप में परिभाषित किया जाता है और उन्हें ackermann() पर एक आंतरिक कॉल द्वारा अपडेट किया जा रहा है, जबकि बाहरी कॉल उन मूल्यों पर निर्भर करता है जो बदल नहीं रहे हैं। उदाहरण के लिए, के ackermann() के अपने पंजीकृत संस्करण में inner_else खंड पर एक नज़र डालें: यह ackermann(R4, R8) पर कॉल करता है, और अगले विवरण में आर 4 के वर्तमान मूल्य पर निर्भर करता है लेकिन रिकर्सिव कॉल असाइनमेंट कथन तक पहुंचने से पहले आर 4 की सेटिंग को बदल देता है।

दो आम समाधान:

  1. स्थानीय चर के रूप में अपने रजिस्टरों परिभाषित करें और संकलक आप के लिए समारोह प्रति कॉल राज्य का ट्रैक रखने करते हैं।

  2. अपने ackermann() फ़ंक्शन में प्रवेश पर, मैन्युअल रूप से सभी रजिस्टरों की स्थिति को सहेजें और फिर बाहर निकलने पर उसे पुनर्स्थापित करें। हालांकि

समाधान 1 आसान है, मैं अपने शिक्षक, समाधान 2 पसंद कर सकते हैं क्योंकि यह एक संकलक द्वारा प्रयोग किया जाता है अपने उत्पन्न विधानसभा कोड में वास्तविक रजिस्टर प्रबंधन से निपटने के लिए तकनीक की तरह दिखाता है संदेह है।

+0

दूसरे समाधान के संबंध में, मुझे किस रजिस्ट्रार को धक्का देना चाहिए और पॉप करना चाहिए? समारोह में जहां मैं उन्हें बहाल करना चाहिए (पॉप)? आपके उत्तर के लिए धन्यवाद :) – mgus

+0

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

+0

मैं सुरक्षित तरीके से जाना पसंद करता हूं .. मैंने जो कहा है उसके अनुसार मैंने कोड बदल दिया लेकिन अभी भी काम नहीं करता है।सबसे पहले मैंने 6 ग्लोबल वैरिएबल ** int ए, बी, सी, डी, ई, एफ; ** और फिर असाइनमेंट के बाद एकरमेन फ़ंक्शन में ** आर 4 = एम; आर 5 = एन; ** मैंने जोड़ा:/* पुश */ ए = आर 4; बी = आर 5; सी = आर 7; डी = आर 8; ई = आर 9; एफ = आर 10; और प्रत्येक वापसी से पहले मैंने जोड़ा:/* पीओपी */ ए = आर 4; बी = आर 5; सी = आर 7; डी = आर 8; ई = आर 9; एफ = आर 10; मैं क्या गलत कर रहा हूं? कृपया मदद करें :) धन्यवाद @Marc Cohen – mgus