2 বাইট সংরক্ষণের জন্য লিওকে ধন্যবাদ
/ow;B1dt&w;31J
\i@/01dt,t&w.2,+k;d&+
এটি অনলাইন চেষ্টা করুন!
প্রায় অবশ্যই অনুকূল নয়। নিয়ন্ত্রণ প্রবাহটি মোটামুটি বিস্তৃত এবং আমি পূর্ববর্তী সংস্করণগুলির তুলনায় যে কতগুলি বাইট সংরক্ষণ করেছি তা নিয়ে আমি বেশ খুশি, আমার এমন অনুভূতি রয়েছে যে আমি এমন কিছুগুলিকে জটিল করে তুলছি যা একটি সহজ এবং খাটো সমাধান হতে পারে ।
ব্যাখ্যা
প্রথমত, আমাকে অ্যালিসের ফেরত ঠিকানা স্ট্যাক (আরএএস) এর কিছুটা বিস্তৃত করতে হবে। অন্যান্য অনেক ছত্রাকজনিতের মতো অ্যালিসেরও কোডে চারপাশে লাফানোর একটি কমান্ড রয়েছে। তবে, আপনি যেখানে থেকে এসেছেন সেখানে ফিরে যাওয়ার কমান্ডও রয়েছে, যা আপনাকে সাব্রুটাইনগুলি বেশ সুবিধাজনকভাবে প্রয়োগ করতে দেয়। অবশ্যই, এটি একটি 2 ডি ভাষা হওয়ায় সাবরুটাইনগুলি কেবলমাত্র কনভেনশন দ্বারা বিদ্যমান। আপনাকে রিটার্ন কমান্ড (বা সাবরুটিনের যে কোনও মুহুর্তে) ছাড়া অন্য উপায়ে সাব্রুটিন প্রবেশ করা বা ছেড়ে দেওয়া থেকে বিরত কিছু নেই, এবং আপনি আরএএস কীভাবে ব্যবহার করেন তার উপর নির্ভর করে আর কোনওভাবেই পরিষ্কার জাম্প / রিটার্নের স্তরক্রম নাও থাকতে পারে।
সাধারণভাবে, লাফানোর আগে জাম্প কমান্ডটি j
বর্তমান আইপি ঠিকানাটি আরএএসের দিকে ঠেলে দিয়ে প্রয়োগ করা হয়। রিটার্ন কমান্ডটি k
তখন আরএএসের একটি ঠিকানা পপ করে এবং সেখানে লাফ দেয়। আরএএস ফাঁকা থাকলে, k
কিছুতেই না করে।
আরএএসকে চালিত করার অন্যান্য উপায়ও রয়েছে। এর মধ্যে দুটি এই প্রোগ্রামের জন্য প্রাসঙ্গিক:
w
আর কোথাও না লাফিয়ে বর্তমান আইপি ঠিকানাটি আরএএসের দিকে ঠেলে দেয় । আপনি যদি এই আদেশটি পুনরাবৃত্তি করেন তবে আপনি সহজ লুপগুলি সহজেই সুবিধার্থে লিখতে পারেন &w...k
যা আমি ইতিমধ্যে পূর্ববর্তী উত্তরে করেছি done
J
এর মতো j
তবে আরএএস-এর বর্তমান আইপি ঠিকানাটি মনে নেই ।
এটিও গুরুত্বপূর্ণ যে, আরএএস আইপিটির দিকনির্দেশ সম্পর্কে কোনও তথ্য সংরক্ষণ করে না । সুতরাং কোনও ঠিকানায় ফিরে আসা k
সর্বদা বর্তমান আইপি দিকটি (এবং তাই আমরা কার্ডিনাল বা অর্ডিনাল মোডে থাকুক না কেন) সংরক্ষণ করব এবং নির্বিশেষে আমরা কীভাবে পাস করেছি j
বা w
যে আইপি ঠিকানাটিকে প্রথম স্থানে ফেলেছে তা নির্বিশেষে ।
সেই উপায়টির সাথে, আসুন উপরের প্রোগ্রামটির সাবরোটাইনটি অনুসন্ধান করে শুরু করা যাক:
01dt,t&w.2,+k
এই সাবরুটাইন স্ট্যাকের নীচের উপাদানটিকে টানিয়ে দেয়, এন এবং তারপরে ফিবোনাচি সংখ্যা F (n) এবং F (n + 1) গণনা করে (এগুলি স্ট্যাকের উপরে রেখে)। আমাদের কখনই এফ (এন + 1) লাগবে না, তবে &w...k
লুপগুলি কীভাবে আরএএসের সাথে যোগাযোগ করে (কোন ধরণের এই লুপগুলি সাব্রোটিনের শেষে হওয়া প্রয়োজন) এর কারণে এটি সাব্রোটিনের বাইরে ফেলে দেওয়া হবে । আমরা শীর্ষের পরিবর্তে নীচে থেকে উপাদানগুলি নিচ্ছি এর কারণ হ'ল এটি আমাদের স্ট্যাকটিকে আরও একটি কাতারের মতো আচরণ করতে দেয়, যার অর্থ আমরা সমস্ত ফিবোনাচি নম্বরগুলি অন্য কোথাও সঞ্চয় না করে এক সাথে গণনা করতে পারি।
এই সাবরোটাইন কীভাবে কাজ করে তা এখানে:
Stack
01 Push 0 and 1, to initialise Fibonacci sequence. [n ... 0 1]
dt, Pull bottom element n to top. [... 0 1 n]
t&w Run this loop n times... [... F(i-2) F(i-1)]
. Duplicate F(i-1). [... F(i-2) F(i-1) F(i-1)]
2, Pull up F(i-2). [... F(i-1) F(i-1) F(i-2)]
+ Add them together to get F(i). [... F(i-1) F(i)]
k End of loop.
লুপটির শেষটি কিছুটা জটিল। স্ট্যাকের 'ডাব্লু' ঠিকানার একটি অনুলিপি থাকে না কেন, এটি পরবর্তী পুনরাবৃত্তি শুরু করে। এগুলি হ্রাস হয়ে গেলে, ফলাফল কীভাবে সাবরোটাইন ডাকা হয়েছিল তার উপর নির্ভর করে। যদি সাবরুটিনকে 'জে' দিয়ে ডাকা হয়, সর্বশেষ 'কে' সেখানে ফিরে আসে, সুতরাং লুপ শেষটি সাব্রোটিনের প্রত্যাবর্তনের হিসাবে দ্বিগুণ হয়। যদি সাবরুটিনকে 'জে' দিয়ে ডাকা হত, এবং স্ট্যাকের পূর্ব থেকে কোনও ঠিকানা এখনও রয়েছে, আমরা সেখানে লাফিয়ে যাব। এর অর্থ যদি সাব্রোটিনকে একটি বাহ্যিক লুপে নিজেই ডাকা হত, এই 'কে' তার শুরুতে ফিরে আসে বাহ্যিক লুপের । যদি সাব্রোটিনকে 'জে' দিয়ে ডাকা হত তবে আরএএস এখন খালি থাকে, তবে এই 'কে' কিছুই করে না এবং আইপি কেবল লুপের পরে চলতে থাকে। আমরা প্রোগ্রামটিতে এই তিনটি কেসই ব্যবহার করব।
পরিশেষে, প্রোগ্রাম নিজেই।
/o....
\i@...
দশমিক পূর্ণসংখ্যা পড়তে এবং মুদ্রণের জন্য এগুলি কেবল দুটি দ্রুত ভ্রমণ Ord
এর পরে i
, এমন একটি রয়েছে w
যা দ্বিতীয়টির কারণে সাবরোটিনে যাওয়ার আগে বর্তমান অবস্থানটি মনে করে /
। সাবরুটিন এই প্রথম আবাহন নির্ণয় F(n)
এবং F(n+1)
ইনপুটের n
। এরপরে আমরা এখানে ফিরে এলাম, তবে আমরা এখন পূর্ব দিকে চলে যাচ্ছি, সুতরাং কার্ডিনাল মোডে থাকা প্রোগ্রাম অপারেটরদের বাকি। মূল প্রোগ্রামটি এরকম দেখাচ্ছে:
;B1dt&w;31J;d&+
^^^
এখানে 31J
সাবরোটিনের আরেকটি কল এবং এটি একটি ফাইওনাচি নম্বর গণনা করে।
Stack
[F(n) F(n+1)]
; Discard F(n+1). [F(n)]
B Push all divisors of F(n). [d_1 d_2 ... d_p]
1 Push 1. This value is arbitrary. [d_1 d_2 ... d_p 1]
The reason we need it is due to
the fact that we don't want to run
any code after our nested loops, so
the upcoming outer loop over all
divisors will *start* with ';' to
discard F(d+1). But on the first
iteration we haven't called the
subroutine yet, so we need some
dummy value we can discard.
dt&w Run this loop once for each element [d_1 d_2 ... d_p 1]
in the stack. Note that this is once OR
more than we have divisors. But since [d_i d_(i+1) ... F(d_(i-1)) F(d_(i-1)+1)]
we're treating the stack as a queue,
the last iteration will process the
first divisor for a second time.
Luckily, the first divisor is always
1 and F(1) = 1, so it doesn't matter
how often we process this one.
; Discard the dummy value on the [d_1 d_2 ... d_p]
first iteration and F(d+1) of OR
the previous divisor on subsequent [d_i d_(i+1) ... F(d_(i-1))]
iterations.
31J Call the subroutine without pushing [d_(i+1) ... F(d_i) F(d_i+1)]
the current address on the RAS.
Thereby, this doubles as our outer
loop end. As long as there's an
address left from the 'w', the end
of the subroutine will jump there
and start another iteration for the
next divisor. Once that's done, the
'k' at the end of the subroutine will
simply do nothing and we'll continue
after it.
; Discard the final F(d_i+1).
d&+ Get the stack depth D and add the top [final result]
D+2 values. Of course that's two more
than we have divisors, but the stack is
implicitly padded with zeros, so that
doesn't matter.