*(>:^]*(*>{<-!<:^>[:((-<)<(<!-)>>-_)_<<]>:]<]]}*<)]*(:)*=<*)>]
-ln
कमांड-लाइन झंडे (इसलिए +4 बाइट्स) के साथ चलाने की आवश्यकता है । 0
समग्र संख्या के लिए और 1
primes के लिए प्रिंट ।
इसे ऑनलाइन आज़माएं!
मुझे लगता है कि यह पहला गैर-तुच्छ ढेर बिल्लियाँ कार्यक्रम है।
व्याख्या
एक त्वरित ढेर बिल्लियों परिचय:
- स्टैक कैट्स ढेर के एक अनंत टेप पर चल रही है, एक टेप सिर के साथ एक मौजूदा ढेर पर इंगित करता है। प्रत्येक स्टैक को शुरू में शून्य की अनंत राशि से भरा जाता है। मैं आमतौर पर अपने शब्दों में इन शून्य को अनदेखा करूंगा, इसलिए जब मैं कहता हूं "स्टैक के नीचे" मेरा मतलब सबसे कम गैर-शून्य मान है और अगर मैं कहता हूं "स्टैक खाली है" तो मेरा मतलब है कि इस पर केवल शून्य है।
- कार्यक्रम शुरू होने से पहले, एक
-1
प्रारंभिक स्टैक पर धकेल दिया जाता है, और फिर पूरे इनपुट को उसी के ऊपर धकेल दिया जाता है। इस स्थिति में, -n
ध्वज के कारण , इनपुट को दशमलव पूर्णांक के रूप में पढ़ा जाता है।
- कार्यक्रम के अंत में, आउटपुट के लिए वर्तमान स्टैक का उपयोग किया जाता है। यदि
-1
तल पर है, तो इसे नजरअंदाज कर दिया जाएगा। फिर से, -n
ध्वज के कारण , स्टैक से मानों को लाइनफीड-अलग दशमलव पूर्णांक के रूप में मुद्रित किया जाता है।
- स्टैक कैट्स एक प्रतिवर्ती कार्यक्रम भाषा है: कोड का हर टुकड़ा पूर्ववत किया जा सकता है (स्टैक बिल्लियों के बिना एक स्पष्ट जानकारी का ट्रैक रखना)। विशेष रूप से, कोड के किसी भी भाग को उल्टा करने के लिए, आप बस यह दर्पण, जैसे
<<(\-_)
हो जाता है (_-/)>>
। यह डिज़ाइन लक्ष्य भाषा में किस प्रकार के ऑपरेटरों और नियंत्रण प्रवाह निर्माण पर काफी गंभीर प्रतिबंध लगाता है, और आप किस प्रकार के कार्यों को वैश्विक मेमोरी स्थिति पर गणना कर सकते हैं।
यह सब बंद करने के लिए, प्रत्येक स्टैक कैट्स प्रोग्राम को आत्म-सममित होना होगा। आप देख सकते हैं कि उपरोक्त स्रोत कोड के मामले में ऐसा नहीं है। यह वह -l
झंडा है जिसके लिए यह है: यह केंद्र के लिए पहले वर्ण का उपयोग करते हुए, कोड को बाईं ओर दर्पण को दिखाता है। इसलिए वास्तविक कार्यक्रम है:
[<(*>=*(:)*[(>*{[[>[:<[>>_(_-<<(-!>)>(>-)):]<^:>!->}<*)*[^:<)*(>:^]*(*>{<-!<:^>[:((-<)<(<!-)>>-_)_<<]>:]<]]}*<)]*(:)*=<*)>]
पूरे कोड के साथ प्रभावी ढंग से प्रोग्रामिंग अत्यधिक गैर-तुच्छ और अचिंत्य है और वास्तव में अभी तक पता नहीं चला है कि एक मानव संभवतः कैसे कर सकता है। हम सरल कार्यों के लिए इस तरह के कार्यक्रम को मजबूर कर चुके हैं, लेकिन हाथ से कहीं भी नहीं जा सकते। सौभाग्य से, हमने एक मूल पैटर्न पाया है जो आपको कार्यक्रम के एक आधे हिस्से को अनदेखा करने की अनुमति देता है। हालांकि, यह निश्चित रूप से सबप्टिमल है, यह वर्तमान में स्टैक कैट्स में प्रभावी ढंग से प्रोग्राम करने का एकमात्र ज्ञात तरीका है।
तो इस उत्तर में, उक्त पैटर्न का टेम्प्लेट यह है (इसमें कुछ परिवर्तनशीलता है कि इसे कैसे निष्पादित किया जाता है):
[<(...)*(...)>]
जब प्रोग्राम शुरू होता है, तो स्टैक टेप इस तरह दिखता है (इनपुट के लिए 4
, कहें):
4
... -1 ...
0
^
[
चाल बाईं ओर ढेर के शीर्ष (और साथ टेप सिर) - हम फोन इस "धक्का"। और <
टेप हेड को अकेले घुमाता है। इसलिए पहले दो आदेशों के बाद, हमें यह स्थिति मिली है:
... 4 -1 ...
0 0 0
^
अब (...)
एक लूप है जिसे सशर्त के रूप में काफी आसानी से उपयोग किया जा सकता है: लूप में प्रवेश किया जाता है और केवल तब छोड़ा जाता है जब वर्तमान स्टैक के शीर्ष सकारात्मक होता है। चूंकि, यह वर्तमान में शून्य है, हम कार्यक्रम के पूरे पहले आधे हिस्से को छोड़ देते हैं। अब सेंटर कमांड है *
। यह बस है XOR 1
, यानी यह स्टैक के शीर्ष का सबसे कम महत्वपूर्ण बिट टॉगल करता है, और इस मामले 0
में एक में बदल जाता है 1
:
... 1 4 -1 ...
0 0 0
^
अब हम दर्पण छवि का सामना करते हैं (...)
। इस बार ढेर के शीर्ष सकारात्मक है और हम कर कोड दर्ज करें। इससे पहले कि हम देखते हैं कि कोष्ठक के अंदर क्या चल रहा है, मुझे समझाएं कि हम आखिर में कैसे लपेटेंगे: हम यह सुनिश्चित करना चाहते हैं कि इस ब्लॉक के अंत में, हमारे पास एक सकारात्मक मूल्य पर फिर से टेप सिर हो (ताकि पाश एक एकल पुनरावृत्ति के बाद समाप्त हो जाता है और एक रेखीय सशर्त के रूप में बस प्रयोग किया जाता है), यह सही करने के लिए ढेर उत्पादन रखती है और के ढेर सही है कि कि एक रखती है -1
। यदि ऐसा है, तो हम लूप छोड़ते हैं, >
आउटपुट वैल्यू पर जाते हैं और ]
इसे पुश करते हैं -1
ताकि हमारे पास आउटपुट के लिए एक साफ स्टैक हो।
वह यह है कि। अब कोष्ठक के अंदर हम जो कुछ भी करना चाहते हैं, हम प्राणशक्ति की जाँच कर सकते हैं जब तक हम यह सुनिश्चित करते हैं कि हम अंत में पिछले पैराग्राफ में वर्णित चीजों को सेट करें (जो आसानी से कुछ धक्का और टेप सिर हिलाने के साथ किया जा सकता है)। मैंने पहली बार विल्सन के प्रमेय के साथ समस्या को हल करने की कोशिश की, लेकिन 100 बाइट्स में अच्छी तरह से समाप्त हो गया, क्योंकि स्क्वैर्ड फैक्टरियल कम्प्यूटेशन वास्तव में स्टैक कैट्स में काफी महंगा है (कम से कम मुझे एक छोटा रास्ता नहीं मिला है)। इसलिए मैं ट्रायल डिवीजन के बजाय गया और यह वास्तव में बहुत सरल निकला। आइए पहले रेखीय बिट को देखें:
>:^]
आप उनमें से दो कमांड देख चुके हैं। इसके अलावा, :
वर्तमान स्टैक के शीर्ष दो मानों को स्वैप करता है और ^
XORs को दूसरा मान शीर्ष मूल्य में देता है। यह :^
एक खाली स्टैक पर एक मूल्य को डुप्लिकेट करने के लिए एक सामान्य पैटर्न बनाता है (हम मूल्य के शीर्ष पर एक शून्य खींचते हैं और फिर शून्य को चालू करते हैं 0 XOR x = x
)। तो इसके बाद, हमारा टेप इस तरह दिखता है:
4
... 1 4 -1 ...
0 0 0
^
ट्रायल डिवीजन एल्गोरिथ्म जो मैंने लागू किया है वह इनपुट के लिए काम नहीं करता है 1
, इसलिए हमें उस मामले में कोड को छोड़ देना चाहिए। हम आसानी 1
से 0
और अन्य सभी चीजों के साथ सकारात्मक मूल्यों के लिए मैप कर सकते हैं *
, इसलिए यहां बताया गया है कि हम यह कैसे करते हैं:
*(*...)
यही कारण है कि हम बारी है 1
में 0
, कोड का एक बड़ा हिस्सा छोड़ अगर हम वास्तव में मिलता है 0
, लेकिन अंदर हम तुरंत पूर्ववत *
ताकि हम अपने इनपुट मूल्य वापस मिलता है। हमें बस फिर से यह सुनिश्चित करने की आवश्यकता है कि हम कोष्ठक के अंत में एक सकारात्मक मूल्य पर समाप्त हो जाएं ताकि वे लूपिंग शुरू न करें। सशर्त के अंदर, हम एक स्टैक को दाईं ओर घुमाते हैं >
और फिर मुख्य ट्रायल डिवीजन लूप शुरू करते हैं:
{<-!<:^>[:((-<)<(<!-)>>-_)_<<]>:]<]]}
ब्रेसिज़ (कोष्ठकों के विपरीत) एक अलग प्रकार के लूप को परिभाषित करते हैं: यह एक डू-टाइम लूप है, जिसका अर्थ है कि यह हमेशा कम से कम एक चलना के लिए चलता है। अन्य अंतर समाप्ति की स्थिति है: लूप में प्रवेश करते समय स्टैक कैट को वर्तमान स्टैक के शीर्ष मूल्य ( 0
हमारे मामले में) याद है। लूप तब तक चलेगा जब तक कि एक ही मूल्य पुनरावृत्ति के अंत में दिखाई नहीं देता। यह हमारे लिए सुविधाजनक है: प्रत्येक पुनरावृत्ति में हम बस अगले संभावित विभाजक के शेष भाग की गणना करते हैं और इसे इस स्टैक पर स्थानांतरित करते हैं जिसे हम लूप शुरू कर रहे हैं। जब हम एक भाजक पाते हैं, तो शेष भाग 0
बंद हो जाता है। हम शुरू होने वाले विभाजकों को आजमाएंगे n-1
और फिर उन्हें घटाएंगे 1
। इसका मतलब है कि क) हम जानते हैं कि जब हम पहुंचेंगे तो यह समाप्त हो जाएगा1
नवीनतम और बी पर) हम तब निर्धारित कर सकते हैं कि नंबर प्राइम है या नहीं, हमने जो आखिरी डिविज़र का निरीक्षण किया है (यदि यह 1
, यह एक प्राइम है, अन्यथा यह नहीं है)।
चलो उसे करें। शुरुआत में एक छोटा रैखिक खंड है:
<-!<:^>[:
आप जानते हैं कि उनमें से अधिकांश अब तक क्या करते हैं। नए आदेश हैं -
और !
। स्टैक कैट्स में इंक्रीमेंट या डिक्रीमेंट ऑपरेटर्स नहीं होते हैं। हालाँकि -
, इसमें (नकार, यानी गुणा से -1
) और !
(बिटवाइस नहीं, यानी गुणा -1
और घटाव) है। इन्हें या तो वेतन वृद्धि !-
, या वेतन वृद्धि में जोड़ा जा सकता है -!
। तो हम n
शीर्ष पर की प्रतिलिपि को घटाते हैं -1
, फिर n
बाईं ओर स्टैक पर एक और प्रतिलिपि बनाते हैं , फिर नए परीक्षण विभाजक को लाते हैं और इसे नीचे रखते हैं n
। तो पहली पुनरावृत्ति पर, हमें यह मिलता है:
4
3
... 1 4 -1 ...
0 0 0
^
आगे पुनरावृत्तियों पर, 3
अगले परीक्षण विभाजक के साथ बदल दिया जाएगा और इसी तरह (जबकि n
इस बिंदु पर हमेशा की दो प्रतियां एक ही मूल्य होगी)।
((-<)<(<!-)>>-_)
यह मोडुलो गणना है। चूंकि लूप सकारात्मक मूल्यों पर समाप्त हो जाते हैं, इसलिए विचार शुरू करना है -n
और बार-बार ट्रायल डिवीजन d
को इसमें जोड़ना है जब तक कि हमें सकारात्मक मूल्य नहीं मिलता है। एक बार जब हम करते हैं, तो हम परिणाम को घटा देते हैं d
और यह हमें शेष देता है। यहाँ मुश्किल सा यह है कि हम बस -n
स्टैक के ऊपर नहीं डाल सकते हैं और एक लूप शुरू कर सकते हैं जो जोड़ता है d
: यदि स्टैक के शीर्ष नकारात्मक है, तो लूप दर्ज नहीं किया जाएगा। ऐसी एक प्रतिवर्ती प्रोग्रामिंग भाषा की सीमाएं हैं।
इसलिए इस मुद्दे को दरकिनार करने के लिए, हम n
स्टैक के शीर्ष पर शुरुआत करते हैं , लेकिन इसे केवल पहले पुनरावृत्ति पर नकारते हैं। फिर, कि यह लगता है की तुलना में सरल लगता है ...
(-<)
जब स्टैक का शीर्ष सकारात्मक होता है (केवल पहली पुनरावृत्ति पर), तो हम इसके साथ नकारात्मक करते हैं -
। हालांकि, हम अभी ऐसा नहीं कर सकते (-)
क्योंकि तब हम नहीं किया जाएगा छोड़ने पाश जब तक -
दो बार लागू किया गया था। इसलिए हम एक सेल को छोड़ <
देते हैं क्योंकि हम जानते हैं कि वहाँ एक सकारात्मक मूल्य है ( 1
)। ठीक है, इसलिए अब हमने n
पहले पुनरावृत्ति पर भरोसा किया । लेकिन हमारे पास एक नई समस्या है: टेप हेड अब पहले पुनरावृति पर हर दूसरे की तुलना में एक अलग स्थिति में है। इससे पहले कि हम आगे बढ़ें, हमें इसे मजबूत करना होगा। अगले <
टेप सिर छोड़ दिया है। पहली यात्रा पर स्थिति:
-4
3
... 1 4 -1 ...
0 0 0 0
^
और दूसरा पुनरावृत्ति पर (याद रखें कि हमने अब d
एक बार जोड़ा है -n
):
-1
3
... 1 4 -1 ...
0 0 0
^
अगली सशर्त इन रास्तों को फिर से मिला देती है:
(<!-)
पहले पुनरावृत्ति पर टेप सिर एक शून्य पर इंगित करता है, इसलिए यह पूरी तरह से छोड़ दिया जाता है। आगे पुनरावृत्तियों पर, टेप हेड एक पर इंगित करता है, इसलिए हम इसे निष्पादित करते हैं, बाईं ओर जाते हैं और वहां सेल बढ़ाते हैं। चूंकि हम जानते हैं कि सेल शून्य से शुरू होती है, यह अब हमेशा सकारात्मक होगी ताकि हम लूप छोड़ सकें। यह सुनिश्चित करता है कि हम हमेशा मुख्य स्टैक के बचे दो स्टैक को समाप्त करते हैं और अब वापस आ सकते हैं >>
। फिर मोडुलो लूप के अंत में हम करते हैं -_
। आप पहले से ही जानते हैं -
। XOR के लिए _
क्या घटाना ^
है: यदि स्टैक के ऊपर है a
और नीचे मूल्य है, b
तो वह इसके a
साथ बदल देता है b-a
। चूँकि हमने पहले नकारा a
था, फिर भी -_
बदल a
जाता है b+a
, जिससे जुड़ जाता हैd
हमारे कुल में चल रहा है।
लूप समाप्त होने के बाद (हम सकारात्मक रूप से पहुंच गए हैं) मान, टेप इस तरह दिखता है:
2
3
... 1 1 4 -1 ...
0 0 0 0
^
बाएं-सबसे अधिक मूल्य कोई भी सकारात्मक संख्या हो सकती है। वास्तव में, यह पुनरावृत्तियों की संख्या शून्य से एक है। अब एक और छोटी रैखिक बिट है:
_<<]>:]<]]
जैसा कि मैंने पहले कहा था कि हमें d
वास्तविक शेष ( 3-2 = 1 = 4 % 3
) प्राप्त करने के लिए परिणाम को घटाना होगा , इसलिए हम सिर्फ _
एक बार और करते हैं। अगला, हमें उस स्टैक को साफ करने की आवश्यकता है जिसे हम बाईं ओर बढ़ रहे हैं: जब हम अगले भाजक की कोशिश करते हैं, तो काम करने के लिए पहले पुनरावृत्ति के लिए इसे फिर से शून्य होना चाहिए। इसलिए हम वहां जाते हैं और उस पॉजिटिव वैल्यू को दूसरे हेल्पर स्टैक से धक्का देते हैं <<]
और फिर दूसरे के साथ हमारे ऑपरेशनल स्टैक पर वापस जाते हैं >
। हम d
साथ खींचते हैं :
और इसे पीछे के -1
साथ धक्का ]
देते हैं और फिर हम शेष को अपने सशर्त स्टैक पर ले जाते हैं <]]
। यह ट्रायल डिवीजन लूप का अंत है: यह तब तक जारी रहता है जब तक कि हमें एक शून्य शेष नहीं मिलता है, जिस स्थिति में बाईं ओर स्टैक होता हैn
का सबसे बड़ा भाजक (के अलावा n
)।
लूप के समाप्त होने के बाद, *<
इनपुट के साथ पथ जुड़ने से ठीक पहले हम वहाँ हैं 1
। *
बस एक में शून्य हो जाता है 1
, जो हम कुछ देर में की आवश्यकता होगी, और फिर हम साथ भाजक में ले जाएँ <
(ताकि हम इनपुट के लिए के रूप में ही ढेर पर हैं 1
)।
इस बिंदु पर यह तीन विभिन्न प्रकार के आदानों की तुलना करने में मदद करता है। सबसे पहले, विशेष मामला n = 1
जहां हमने उस ट्रायल डिवीजन सामान में से कोई भी नहीं किया है:
0
... 1 1 -1 ...
0 0 0
^
फिर, हमारा पिछला उदाहरण n = 4
, एक समग्र संख्या:
2
1 2 1
... 1 4 -1 1 ...
0 0 0 0
^
और अंत में n = 3
, एक अभाज्य संख्या:
3
1 1 1
... 1 3 -1 1 ...
0 0 0 0
^
इसलिए प्राइम नंबरों के लिए, हमारे पास 1
इस स्टैक पर है, और कंपोजिट नंबरों के लिए हमारे पास या तो 0
पॉजिटिव नंबर है 2
। हम इस स्थिति को चालू करते हैं 0
या 1
हमें निम्नलिखित अंतिम कोड कोड की आवश्यकता होती है:
]*(:)*=<*
]
बस इस मूल्य को दाईं ओर धकेलता है। तब *
सशर्त स्थिति को बहुत सरल बनाने के लिए उपयोग किया जाता है: कम से कम महत्वपूर्ण बिट को टॉगल करके, हम 1
(प्राइम) को 0
, 0
(समग्र) सकारात्मक मूल्य में बदल देते हैं 1
, और अन्य सभी सकारात्मक मूल्य अभी भी सकारात्मक बने रहेंगे। अब हमें केवल 0
और केवल सकारात्मक के बीच अंतर करने की जरूरत है । वहीं हम दूसरे का उपयोग करते हैं (:)
। यदि स्टैक का शीर्ष है 0
(और इनपुट एक प्रमुख था), तो यह बस छोड़ दिया जाता है। लेकिन अगर स्टैक के शीर्ष सकारात्मक है (और इनपुट एक समग्र संख्या थी) यह इसके साथ स्वैप करता है 1
, ताकि हम अब इसके 0
विपरीत और1
primes के लिए - केवल दो अलग-अलग मूल्य। बेशक, वे इसके विपरीत हैं जो हम आउटपुट करना चाहते हैं, लेकिन यह आसानी से दूसरे के साथ तय हो गया है *
।
अब सभी अब सिर्फ़ हमारे आसपास के ढांचे से उम्मीद के ढेर के पैटर्न को बहाल करना है: एक सकारात्मक मूल्य पर टेप सिर सही करने के लिए ढेर के शीर्ष पर परिणाम, और एक एकल -1
के ढेर सही पर है कि । यह वही =<*
है जिसके लिए है =
दो आसन्न ढेर के शीर्ष स्वैप, जिससे -1
परिणाम के दाईं ओर बढ़ रहा है , जैसे इनपुट के लिए 4
फिर से:
2 0
1 3
... 1 4 1 -1 ...
0 0 0 0 0
^
फिर हम बस बाएं से चलते हैं <
और उस शून्य को एक में बदल देते हैं *
। और वही जो है।
यदि आप प्रोग्राम को कैसे काम करते हैं, इसके बारे में गहराई से खुदाई करना चाहते हैं, तो आप डिबग विकल्पों का उपयोग कर सकते हैं। या तो -d
झंडा जोड़ें और "
जहाँ भी आप इस तरह की वर्तमान मेमोरी स्थिति देखना चाहते हैं सम्मिलित करें , या पूरे कार्यक्रम का पूरा पता लगाने के लिए-D
ध्वज का उपयोग करें । वैकल्पिक रूप से, आप टिमवी के एसोटेरिकैड का उपयोग कर सकते हैं जिसमें स्टेप-बाय-स्टेप डिबगर के साथ एक स्टैक कैट्स दुभाषिया शामिल है।