এবং সংকলকরা পুনরাবৃত্ত যুক্তিকে সমতুল্য নন-রিকার্সিভ লজিকে রূপান্তর করতে পারে?


15

আমি এফ # শিখছি এবং আমি যখন সি # প্রোগ্রামিং করছি তখন কীভাবে আমার মনে হয় তা প্রভাবিত করতে শুরু করে। সেই লক্ষ্যে, আমি ফলাফল পুনরায় পাঠযোগ্যতার উন্নতি বোধ করি এবং আমি এটি পুনরায় স্ট্যাকের ওভারফ্লোতে প্রবাহিত করার কল্পনাও করতে পারি না বলে আমি পুনরাবৃত্তি ব্যবহার করছি।

এটি আমাকে জিজ্ঞাসা করতে পরিচালিত করে যে সংকলকগণ পুনঃবিবেচিত ফাংশনগুলিকে স্বয়ংক্রিয়ভাবে একটি সমতুল্য নন-रिकर्सিভ ফর্মে রূপান্তর করতে পারে কিনা?


টেল কল অপ্টিমাইজেশনটি যদি বেসিক উদাহরণ হিসাবে ভাল তবে এটি যদি কেবল return recursecall(args);আপনার পুনরাবৃত্তির জন্য কাজ করে তবেই আরও কার্যকর জিনিসগুলি স্পষ্টভাবে স্ট্যাক তৈরি করে এবং এটি ঘুরিয়ে দিয়ে সম্ভব হয় তবে আমি সন্দেহ করি তারা করবে
ratchet freak

@ratchet freak: পুনরাবৃত্তির অর্থ "গণনা যা একটি স্ট্যাক ব্যবহার করছে" নয়।
জর্জিও

1
@ জর্জিও আমি জানি তবে একটি স্ট্যাকটি পুনরাবৃত্তিটিকে একটি লুপে রূপান্তর করার সহজতম উপায়
রাচেট ফ্রিক

উত্তর:


21

হ্যাঁ, কিছু ভাষা এবং সংকলক পুনরাবৃত্ত লজিকে নন-রিকার্সিভ লজিকে রূপান্তর করবে। এটি লেজ কল অপ্টিমাইজেশন হিসাবে পরিচিত - নোট করুন যে সমস্ত পুনরাবৃত্তি কলগুলি কল কলটি অপটিমাইজযোগ্য নয়। এই পরিস্থিতিতে, সংকলক ফর্মটির একটি ক্রিয়াকলাপ স্বীকৃত:

int foo(n) {
  ...
  return bar(n);
}

এখানে ভাষাটি চিনতে সক্ষম হয়েছে যে ফলাফলটি ফেরত দেওয়া হচ্ছে অন্য ফাংশন থেকে প্রাপ্ত ফলাফল এবং একটি নতুন স্ট্যাক ফ্রেমের সাহায্যে একটি ফাংশন কলকে একটি জাম্পে পরিবর্তন করতে হবে।

অনুধাবন করুন যে ক্লাসিক কল্পিত পদ্ধতি:

int factorial(n) {
  if(n == 0) return 1;
  if(n == 1) return 1;
  return n * factorial(n - 1);
}

হয় না পরিদর্শন আগমন প্রয়োজনীয় কারণ লেজ কল optimizatable।

এই লেজ কলটি অনুকূলিত করে তুলতে,

int _fact(int n, int acc) {
    if(n == 1) return acc;
    return _fact(n - 1, acc * n);
}

int factorial(int n) {
    if(n == 0) return 1;
    return _fact(n, 1);
}

এই কোডটি gcc -O2 -S fact.cসংকলন করে (-O2 সংকলকটিতে অপ্টিমাইজেশন সক্ষম করতে প্রয়োজনীয়, তবে -O3 এর আরও অনুকূলিতকরণের সাথে এটি মানুষের পক্ষে পড়া শক্ত হয়ে যায় ...)

_fact:
.LFB0:
        .cfi_startproc
        cmpl    $1, %edi
        movl    %esi, %eax
        je      .L2
        .p2align 4,,10
        .p2align 3
.L4:
        imull   %edi, %eax
        subl    $1, %edi
        cmpl    $1, %edi
        jne     .L4
.L2:
        rep
        ret
        .cfi_endproc

একটি অংশ দেখতে পাবেন .L4, jneবরং একটি তুলনায় call(যা একটি নতুন স্ট্যাক ফ্রেম সঙ্গে একটি সাবরুটিন কল না)।

দয়া করে নোট করুন যে এটি সি দ্বারা করা হয়েছিল জাভাতে টেইল কল অপ্টিমাইজেশন শক্ত এবং এটি জেভিএম বাস্তবায়নের উপর নির্ভর করে - লেজ-পুনরাবৃত্তি + জাভা এবং লেজ-পুনরাবৃত্তি + অপ্টিমাইজেশন ব্রাউজ করার জন্য ভাল ট্যাগ সেট। আপনি দেখতে পেতে পারেন যে অন্যান্য জেভিএম ভাষাগুলি লেজ পুনরাবৃত্তিকে আরও ভাল করতে পারে (ক্লোজারটি (যার জন্য টেল কলটি অপ্টিমাইজ করার পুনরাবৃত্তি প্রয়োজন ), বা স্কালা) চেষ্টা করুন।


1
আমি নিশ্চিত নই যে ওপি এটিই জিজ্ঞাসা করছে। রানটাইম কোনও নির্দিষ্ট উপায়ে স্ট্যাক স্পেস ব্যবহার করে বা না খায়, তার অর্থ এই নয় যে ফাংশনটি পুনরাবৃত্ত হয় না।

1
@ ম্যাটফেনউইক আপনি কীভাবে বোঝাতে চাইছেন? "এটি আমাকে জিজ্ঞাসা করতে পরিচালিত করে যে সংকলকগুলি পুনঃবিবেচনামূলক ফাংশনগুলিকে স্বয়ংক্রিয়ভাবে একটি সমতুল্য নন-रिकर्सিভ ফর্মে রূপান্তর করতে পারে" - উত্তরটি "হ্যাঁ কিছু শর্তাধীন"। শর্তগুলি প্রদর্শিত হয়, এবং আমি উল্লেখ করেছি যে টেল কল অপ্টিমাইজেশান সহ কিছু অন্যান্য জনপ্রিয় ভাষায় কিছু আছে।

9

সাবধানে চলুন।

উত্তর হ্যাঁ, তবে সবসময় নয় এবং সবগুলিই নয়। এই পন্থা যা কয়েক বিভিন্ন নাম দ্বারা যায়, কিন্তু আপনি কিছু প্রশংসনীয় নির্ধারক তথ্য পেতে পারেন এখানে এবং উইকিপিডিয়া

আমি "টেইল কল অপ্টিমাইজেশন" নামটি পছন্দ করি তবে অন্যরাও আছেন এবং কিছু লোক এই শব্দটিকে বিভ্রান্ত করবেন।

এটি বলেছে যে উপলব্ধি করার জন্য কয়েকটি গুরুত্বপূর্ণ বিষয় রয়েছে:

  • একটি টেল কল অনুকূলিত করতে, লেজ কলটির জন্য পরামিতিগুলির প্রয়োজন যা কল করার সময় জানা যায়। এর অর্থ যদি পরামিতিগুলির মধ্যে একটির যদি ফাংশনটিতে নিজেই কল হয়, তবে এটি লুপে রূপান্তরিত হতে পারে না , কারণ এর জন্য বলা লুপের নির্বিচারে বাসা বাঁধার প্রয়োজন যা সংকলনের সময় বাড়ানো যায় না।

  • সি # টিলে কলগুলি নির্ভরযোগ্যভাবে অনুকূল করে না । আইএল এর এমন নির্দেশনা রয়েছে যা এফ # সংকলকটি নির্গত করবে, তবে সি # সংকলকটি এটি বেমানানভাবে নির্গত করবে এবং জেআইটি পরিস্থিতির উপর নির্ভর করে জেআইটি এটি আদৌ করতে পারে বা করতে পারে না। সমস্ত ইঙ্গিতগুলি হল যে আপনার সি # তে আপনার লেজ কলগুলি অনুকূলিত করা উচিত নয়, এটি করার ক্ষেত্রে ওভারফ্লো হওয়ার ঝুঁকিটি উল্লেখযোগ্য এবং বাস্তব


1
আপনি কি নিশ্চিত যে ওপি এটিই জিজ্ঞাসা করছে? আমি যেমন অন্য উত্তরের অধীনে পোস্ট করেছি, কেবল রানটাইম একটি নির্দিষ্ট উপায়ে স্ট্যাক স্পেস ব্যবহার করে বা না খায়, তার অর্থ এই নয় যে ফাংশনটি পুনরাবৃত্ত হয় না।

1
@ ম্যাটফেনউইক এটি প্রকৃতপক্ষে একটি দুর্দান্ত বিষয়, এটি নির্ভর করে, এফ # সংকলক নির্গমনকারী লেজ কল নির্দেশগুলি সম্পূর্ণ পুনরাবৃত্ত যুক্তি বজায় রাখছে, এটি কেবল স্ট্রাইক-স্পেস- পরিবর্তে স্ট্যাক-স্পেস-রিপ্লেসিং ফ্যাশনে এটি কার্যকর করার জন্য জেআইটিকে নির্দেশ দিচ্ছে বর্ধমান, তবে অন্যান্য সংকলকগুলি আক্ষরিকভাবে একটি লুপে সংকলন করতে পারে। (প্রযুক্তিগতভাবে জেআইটি একটি লুপ বা সম্ভবত লুপস ফ্যাশনে সংকলন করছে যদি লুপটি সম্পূর্ণ সামনে থাকে)
জিমি হোফা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.