2010-06-28 16 views
52

Boost preprocessor's capabilities की खोज करने के बाद मुझे खुद को आश्चर्य हुआ: क्या सी 99 प्रीप्रोसेसर ट्यूरिंग पूर्ण है?क्या सी 99 प्रीप्रोसेसर ट्यूरिंग पूरा है?

यदि नहीं, तो क्या यह योग्य नहीं की कमी है?

+7

परिमित और अनंत मशीनें ट्यूरिंग के लिए सीपीपी में लापता बात पूर्णता अनिवार्य रूप से रिकर्सन है, क्योंकि यह इसके बिना लूप नहीं कर सकती है (और वास्तव में काफी सीमित सशर्त है क्योंकि आप सशर्त रूप से मैक्रो के भाग का विस्तार नहीं कर सकते हैं) – Spudd86

उत्तर

28

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

आगे से जुड़े परियोजना के वर्णन से:

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

पॉल Fultz द्वितीय ने जवाब काफी प्रभावशाली और निश्चित रूप से करीब से मैंने सोचा था कि पूर्वप्रक्रमक कभी मिल सकता है, लेकिन यह एक सच ट्यूरिंग मशीन नहीं है। सी प्रीप्रोसेसर की कुछ सीमाएं हैं जो इसे एक ट्यूरिंग मशीन जैसे मनमाने ढंग से प्रोग्राम निष्पादित करने से रोकती हैं, भले ही आपके पास अनंत स्मृति और समय हो। एक आंतरिक पहचानकर्ता या किसी मैक्रो नाम पर

  • 63 महत्वपूर्ण प्रारंभिक अक्षर में एक पूर्ण अभिव्यक्ति के भीतर

    • 63 parenthesized अभिव्यक्ति की नेस्टिंग स्तर: C spec की धारा 5.2.4.1 एक सी संकलक के लिए निम्न न्यूनतम सीमा देता है
    • 4095 मैक्रो पहचानकर्ता एक साथ एक तार्किक स्रोत लाइन में
    • 4095 वर्ण एक पूर्व प्रसंस्करण अनुवाद इकाई में परिभाषित

    नीचे काउंटर तंत्र के लिए प्रति मान एक मैक्रो परिभाषा की आवश्यकता होती है, इसलिए मैक्रो परिभाषा सीमा सीमित होगी कि आप कितनी बार लूप कर सकते हैं (EVAL(REPEAT(4100, M, ~)) अपरिभाषित व्यवहार उत्पन्न करेगा)। यह अनिवार्य रूप से प्रोग्राम की जटिलता पर एक टोपी रखता है जिसे आप निष्पादित कर सकते हैं। बहु-स्तर के विस्तार की घोंसले और जटिलता अन्य सीमाओं में से एक को भी प्रभावित कर सकती है।

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

  • +9

    यह उत्तर गलत है, क्योंकि नीचे के 77 बिंदु उत्तर बड़े पैमाने पर दिखाए जाते हैं। कृपया इसे अस्वीकार करें और अधिक उपयोगी उत्तर स्वीकार करें, धन्यवाद। – nightpool

    +0

    यदि आपका मतलब पॉल फुल्टज़ द्वितीय द्वारा 115 बिंदु का उत्तर है: यह इस उत्तर की पुष्टि करता है। – reinierpost

    +0

    सीमा भाषा में ही है, लेकिन कल्पना के कारण नहीं, बल्कि इसलिए हमें भाषा में एल्गोरिदम का मूल्यांकन करने के लिए स्कैन लिखना होगा, जिसमें असीमित संख्या में स्कैन लागू करने के लिए कोई तंत्र नहीं है। –

    4

    यह सीमा के भीतर ट्यूरिंग पूरा हो (क्योंकि वे अनंत राम की जरूरत नहीं है के रूप में सभी कंप्यूटरों हैं)। Boost Preprocessor के साथ आप जो कुछ भी कर सकते हैं, उसे देखें। संपादन पर सवाल उठाने

    जवाब में

    संपादित करें:

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

    सीमित ट्यूरिंग-पूर्णता (ट्यूरिंग-संगतता?) के लिए वास्तव में आवश्यक केवल दो चीजें पुनरावृत्ति/पुनरावर्तन (समकक्ष संरचनाएं) और सशर्त शाखाएं हैं।

    +0

    हाय। यही वास्तव में मेरे प्रश्न को प्रेरित करता था, मैं थोड़ी देर के लिए प्रीप्रोसेसर का उपयोग कर रहा हूं। – Anycorn

    +0

    एआरपी .. हाँ, मुझे प्रश्न पढ़ने के लिए जाएं>< – Cogwheel

    +0

    BOOST_PP के स्रोत कोड में चारों ओर खुदाई करना यह पता लगाने का सबसे अच्छा तरीका है कि यह कैसे किया जाता है। – Cogwheel

    119

    अच्छी मैक्रोज़ सीधे रिकर्सली का विस्तार नहीं करते हैं, लेकिन ऐसे तरीके हैं जिनसे हम इसके आसपास काम कर सकते हैं।

    प्रीप्रोसेसर में रिकर्सन करने का सबसे आसान तरीका एक स्थगित अभिव्यक्ति का उपयोग करना है। एक स्थगित अभिव्यक्ति एक अभिव्यक्ति है जिसके लिए पूरी तरह से विस्तार करने के लिए अधिक स्कैन की आवश्यकता होती है:

    #define EMPTY() 
    #define DEFER(id) id EMPTY() 
    #define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() 
    #define EXPAND(...) __VA_ARGS__ 
    
    #define A() 123 
    A() // Expands to 123 
    DEFER(A)() // Expands to A() because it requires one more scan to fully expand 
    EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan 
    

    यह महत्वपूर्ण क्यों है? वैसे जब एक मैक्रो स्कैन और विस्तार किया जाता है, तो यह एक अक्षम संदर्भ बनाता है। यह अक्षम करने वाला संदर्भ एक टोकन का कारण बनता है, जो वर्तमान में विस्तारित मैक्रो को संदर्भित करता है, जिसे नीला रंग दिया जाता है। इस प्रकार, एक बार इसकी पेंट नीली, मैक्रो अब विस्तार नहीं करेगा। यही कारण है कि मैक्रोज़ बार-बार विस्तार नहीं करते हैं। हालांकि, एक अक्षम करने वाला संदर्भ केवल एक स्कैन के दौरान मौजूद है, इसलिए विस्तार को परिभाषित करके हम अपने मैक्रोज़ को नीले रंग से चित्रित करने से रोक सकते हैं। हमें अभिव्यक्ति के लिए और अधिक स्कैन लागू करने की आवश्यकता होगी। हम क्या कर सकते हैं कि इस EVAL मैक्रो का उपयोग:

    #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) 
    #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) 
    #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) 
    #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) 
    #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__))) 
    #define EVAL5(...) __VA_ARGS__ 
    

    अब अगर हम एक REPEAT मैक्रो प्रत्यावर्तन का उपयोग कर लागू करना चाहते हैं, पहले हम को संभालने के लिए राज्य कुछ वेतन वृद्धि और घटती ऑपरेटरों की जरूरत है:

    #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) 
    #define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ 
    
    #define INC(x) PRIMITIVE_CAT(INC_, x) 
    #define INC_0 1 
    #define INC_1 2 
    #define INC_2 3 
    #define INC_3 4 
    #define INC_4 5 
    #define INC_5 6 
    #define INC_6 7 
    #define INC_7 8 
    #define INC_8 9 
    #define INC_9 9 
    
    #define DEC(x) PRIMITIVE_CAT(DEC_, x) 
    #define DEC_0 0 
    #define DEC_1 0 
    #define DEC_2 1 
    #define DEC_3 2 
    #define DEC_4 3 
    #define DEC_5 4 
    #define DEC_6 5 
    #define DEC_7 6 
    #define DEC_8 7 
    #define DEC_9 8 
    

    अगला हम की जरूरत है इन सभी मैक्रो हम एक पुनरावर्ती REPEAT मैक्रो लिख सकते हैं के साथ अब

    #define CHECK_N(x, n, ...) n 
    #define CHECK(...) CHECK_N(__VA_ARGS__, 0,) 
    
    #define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x)) 
    #define NOT_0 ~, 1, 
    
    #define COMPL(b) PRIMITIVE_CAT(COMPL_, b) 
    #define COMPL_0 1 
    #define COMPL_1 0 
    
    #define BOOL(x) COMPL(NOT(x)) 
    
    #define IIF(c) PRIMITIVE_CAT(IIF_, c) 
    #define IIF_0(t, ...) __VA_ARGS__ 
    #define IIF_1(t, ...) t 
    
    #define IF(c) IIF(BOOL(c)) 
    
    #define EAT(...) 
    #define EXPAND(...) __VA_ARGS__ 
    #define WHEN(c) IF(c)(EXPAND, EAT) 
    

    : कुछ और मैक्रो तर्क करना है। हम अपने आप को दोबारा संदर्भित करने के लिए REPEAT_INDIRECT मैक्रो का उपयोग करते हैं। यह मैक्रो को नीले रंग से चित्रित करने से रोकता है, क्योंकि यह एक अलग स्कैन (और एक अलग अक्षम संदर्भ का उपयोग कर) पर विस्तार करेगा। हम यहां OBSTRUCT का उपयोग करते हैं, जो विस्तार को दो बार रोक देगा। यह आवश्यक है क्योंकि सशर्त WHEN पहले से ही एक स्कैन लागू होता है।

    #define REPEAT(count, macro, ...) \ 
        WHEN(count) \ 
        (\ 
         OBSTRUCT(REPEAT_INDIRECT)() \ 
         (\ 
          DEC(count), macro, __VA_ARGS__ \ 
         ) \ 
         OBSTRUCT(macro) \ 
         (\ 
          DEC(count), __VA_ARGS__ \ 
         ) \ 
        ) 
    #define REPEAT_INDIRECT() REPEAT 
    
    //An example of using this macro 
    #define M(i, _) i 
    EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7 
    

    अब यह उदाहरण काउंटर की सीमाओं के कारण 10 दोहराना तक सीमित है। कंप्यूटर में दोहराना काउंटर की तरह ही सीमित स्मृति से सीमित होगा। एक कंप्यूटर में बस इस सीमा को काम करने के लिए एकाधिक दोहराने वाले काउंटरों को एक साथ जोड़ा जा सकता है। इसके अलावा, हम एक FOREVER मैक्रो निर्धारित कर सकते हैं:

    #define FOREVER() \ 
        ? \ 
        DEFER(FOREVER_INDIRECT)()() 
    #define FOREVER_INDIRECT() FOREVER 
    // Outputs question marks forever 
    EVAL(FOREVER()) 
    

    यह हमेशा के लिए उत्पादन ? करने की कोशिश करेंगे, लेकिन अंत में बंद हो जाएगा क्योंकि वहाँ कोई और अधिक स्कैन लागू किया जा रहा है। अब सवाल यह है कि, अगर हमने इसे असीमित संख्या में स्कैन दिया तो क्या यह एल्गोरिदम पूरा होगा? इसे रोकने की समस्या के रूप में जाना जाता है, और रोकथाम की समस्या की अनिश्चितता साबित करने के लिए ट्यूरिंग पूर्णता आवश्यक है।तो जैसा कि आप देख सकते हैं, प्रीप्रोसेसर ट्यूरिंग पूर्ण भाषा के रूप में कार्य कर सकता है, लेकिन कंप्यूटर की सीमित स्मृति तक सीमित होने की बजाय इसे लागू स्कैन की सीमित संख्या से सीमित किया जाता है।

    +5

    ... वाह। बहुत प्रभावशाली! यहां मैंने सोचा था कि सी 99 प्रीप्रोसेसर निश्चित रूप से पूरा नहीं कर रहा था .. – Earlz

    +0

    +1 बॉक्स से बाहर सोचने के लिए +1 +1 प्रीप्रोसेसर * दिखाने के लिए एक रचनात्मक तरीका है * टेप पर प्रतीक स्कैन कर सकते हैं ;-) (मोड के लिए धन्यवाद विकी को हटाने के लिए ध्वज को स्वीकार करना!)। –

    +0

    मुझे यह पसंद है कि यह एन बार (रिक (एन)) मैक्रोज़ को एन बार पुन: उपयोग करने के लिए कैसे उपयोग करता है। यह बूस्ट प्रीप्रोसेसर से बेहतर है जो ओ (एन) मैक्रोज़ का उपयोग करता है। – qbt937

    4

    ट्यूरिंग पूर्ण होने के लिए, किसी को रिकर्सन को परिभाषित करने की आवश्यकता है जो कभी खत्म नहीं हो सकता है (एक उन्हें एमयू-रिकर्सिव ऑपरेटर - https://en.wikipedia.org/wiki/%CE%9C-recursive_function) कहता है।

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

    तो इस वर्ग के कार्यों को सी प्रीप्रोसेसर द्वारा गणना नहीं की जा सकती है।

    सी प्रीप्रोसेसर केवल सिग्मा-रिकर्सिव ऑपरेटरों की गणना कर सकता है - https://en.wikipedia.org/wiki/Primitive_recursive_function

    जानकारी के लिए मारविन एल Minsky की गणना के पाठ्यक्रम (1967) देखें - संगणना:, प्रेंटिस-हॉल, इंक Englewood Cliffs, न्यू जर्सी आदि

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