সিতে নেস্টেড রুট গণনা করা হচ্ছে


9

আমাকে কেবল পুনরাবৃত্তি ব্যবহার করে নীচের নেস্টেড রুট এক্সপ্রেশন গণনা করতে বলা হয়েছিল ।

এখানে চিত্র বর্ণনা লিখুন

আমি নীচের কোডটি লিখেছি যা কাজ করে, তবে তারা আমাদের কেবল একটি ফাংশন এবং 1 ইনপুট ব্যবহারেরn জন্য অনুমতি দিয়েছিল এবং আমার মতো 2 ব্যবহার করে না। কেউ আমাকে এই কোডটিকে একটি ফাংশনে রূপান্তর করতে সহায়তা করতে পারে যা অভিব্যক্তি গণনা করবে? থেকে ফাংশন ব্যতীত অন্য কোনও গ্রন্থাগার ব্যবহার করতে পারবেন না <math.h>

এন = 10 এর জন্য আউটপুট: 1.757932

double rec_sqrt_series(int n, int m) {
    if (n <= 0)
        return 0;
    if (m > n)
        return 0;
    return sqrt(m + rec_sqrt_series(n, m + 1));
}

double helper(int n) {
    return rec_sqrt_series(n, 1);
}

কেউ আমাকে এই কোডটিকে একটি ফাংশনে রূপান্তর করতে সহায়তা করতে পারে যা অভিব্যক্তি গণনা করবে? কি? আপনি পরিত্রাণ পেতে সাহায্য helper?
4386427

যদি তর্কগুলি ভুল হয়, আমি কল করব abort()(থেকে <stdlib.h>), নিঃশব্দে ফিরে আসবে না 0
কাজ

1
পুনঃটুইট @ পাস্তলেগ কীভাবে অকেজো পুনরাবৃত্তি সম্পর্কে? double nested_root(unsigned n) { double x = 0.0; if (n > 0) { x = nested_root(0); for (unsigned i = n; i > 0; i--) { x = sqrt(i + x); } } return x; }
chux - মনিকা পুনরায় ইনস্টল করুন

1
@ chux-ReinstateMonica: হ্যাঁ, নিয়মের একটি সরল অপব্যবহার।
chqrlie

2
@ ওপেন: যদি অ্যাসাইনমেন্টের লক্ষ্যটি ফাংশনটির একটি পুনরাবৃত্ত প্রকাশের তহবিল ফান্ড করা হয়, তবে সম্ভবত এটি "কেবল পুনরাবৃত্তি" ব্যবহার করে সমস্যার সমাধান করার অনুরোধ করবে না। অবশ্যই একটি সহজ লুপ ফলাফল সহজেই গণনা করতে পারে। যদিও এই প্রশ্নগুলি কার্যভারের আসল পাঠ্য ছাড়াই স্ট্যাক ওভারফ্লোতে পোস্ট করা হয় তখন আমি সাধারণত সন্দেহজনক।
এরিক পোস্টপিসিল

উত্তর:


7

nকাউন্টার হিসাবে উপরের বিটগুলি ব্যবহার করুন :

double rec_sqrt_series(int n)
{
    static const int R = 0x10000;
    return n/R < n%R ? sqrt(n/R+1 + rec_sqrt_series(n+R)) : 0;
}

স্বাভাবিকভাবেই, যে চলমান সমস্যা যখন প্রাথমিক nহয় Rবা তার অধিক। এখানে আরও জটিল সংস্করণ যা কোনও ধনাত্মক মানের জন্য কাজ করে n। এটি কাজ করে:

  • যখন nনেতিবাচক হয়, এটি গণনা করতে উপরের বিটগুলি ব্যবহার করে উপরের সংস্করণটির মতো কাজ করে।
  • যখন nইতিবাচক হয়, যদি এটি এর চেয়ে কম হয় তবে এটি উপরে হিসাবে ফাংশনটি মূল্যায়নের জন্য Rনিজেকে কল করে -n। অন্যথায়, এটি নিজেকে R-1অবহেলা করে বলে। এটি ফাংশনটি যেমন এটি ডাকা হয়েছে তা মূল্যায়ন করে R-1। এটি সঠিক ফলাফল উত্পন্ন করে কারণ সিরিজটি কেবল কয়েক ডজন পুনরাবৃত্তির পরে ভাসমান-বিন্দু বিন্যাসে পরিবর্তন বন্ধ করে দেয় er গভীর সংখ্যার বর্গাকার শিকড়গুলি এত মিশ্রিত হয় যেগুলির কোনও প্রভাব নেই। সুতরাং ফাংশন nএকটি ছোট থ্রেশহোল্ড জুড়ে সমস্ত জন্য একই মান আছে ।
double rec_sqrt_series(int n)
{
    static const int R = 0x100;
    return
        0 < n ? n < R ? rec_sqrt_series(-n) : rec_sqrt_series(1-R)
              : n/R > n%R ? sqrt(-n/R+1 + rec_sqrt_series(n-R)) : 0;
}

ভাল ধারণা, তবে 32-বিট
অন্তর্নিহিত

1
@ chqrlieforyellow blockquotes: নাহ, এ কারণেই Rপৃথক, তাই এটি সুর করা যেতে পারে। n32-এ পৌঁছানোর আগে , রিটার্ন মান আইইইই-754 বাইনারি 64 এর জন্য পরিবর্তন করা বন্ধ করে, এবং এটি 256-এ পৌঁছানোর আগে, রিটার্ন মানটি যুক্তিসঙ্গত ফর্ম্যাটগুলির জন্য পরিবর্তন বন্ধ করে দেয় double। সুতরাং আমি একটি বিকল্প সংস্করণ বিবেচনা করছি যা উপরের ক্ল্যাম্পস ইনপুটগুলিকে রূপান্তর করে R, তবে এটিতে সাইন বিটটি ব্যবহার করা দরকার, এবং আমি এখনও এটি নিয়ে কাজ করছি।
এরিক পোস্টপিসিল

আপনি ব্যবহার করতে পারেন এমন অন্যান্য জুটিবদ্ধ ফাংশন রয়েছে তবে আপনার মতো সহজ কোনও কিছুই নেই। তাদের প্রধান সুবিধাটি হ'ল সাধারণত যে তারা নির্বিচারে নির্ভুলতার সাথে কাজ করে তবে ওপি কখনই এটি প্রয়োজনীয়তার হিসাবে উল্লেখ করেনি।
রুড হেল্ডারম্যান

@ chqrlieforyellow blockquotes: সম্পন্ন হয়েছে। nপ্রস্থ নির্বিশেষে যে কোনও ধনাত্মক জন্য সঠিক উত্তর উত্পাদন করে int
এরিক পোস্টপিসিল

5

গাণিতিকভাবে সূত্রটি রূপান্তর না করা (এটি সম্ভব কিনা তা আমি জানি না), আপনি সত্যিকার অর্থে মাত্র একটি প্যারামিটার ব্যবহার করতে পারবেন না, প্রতিটি উপাদান হিসাবে আপনার দুটি তথ্য দরকার: বর্তমান পদক্ষেপ এবং আসল n। তবে আপনি প্রতারণা করতে পারেন । একটি উপায় হ'ল intপ্যারামিটারে দুটি সংখ্যা এনকোড করা ( এরিক দেখানো হয়েছে )।

আরেকটি উপায় হ'ল nস্থিতিশীল স্থানীয় ভেরিয়েবলে মূলটি সংরক্ষণ করা । প্রথম কলটিতে আমরা nএই স্থিতিশীল ভেরিয়েবলে সংরক্ষণ করি , আমরা পুনরাবৃত্তি শুরু করি এবং শেষ ধাপে আমরা এটিকে সেন্ডিনেল মানটিতে পুনরায় সেট করি:

// fn(i) = sqrt(n + 1 - i + fn(i - 1))
// fn(1) = sqrt(n)
//
// note: has global state
double f(int i)
{
    static const int sentinel = -1;
    static int n = sentinel;

    // outside call
    if (n == sentinel)
    {
        n = i;
        return f(n);
    }

    // last step
    if (i == 1)
    {
        double r = sqrt(n);
        n = sentinel;
        return r;
    }

    return sqrt(n + 1 - i + f(i - 1));
}

স্পষ্টতই static int n = sentinelস্ট্যান্ডার্ড সি নয় কারণ সি-তে sentinelকোনও কমপাইল সময় ধ্রুবক নয় (এটি অদ্ভুত কারণ জিসিসি এবং ক্লাং উভয়ই অভিযোগ করেন না, এমনকি -pedantic)

পরিবর্তে আপনি এটি করতে পারেন:

enum Special { Sentinel = -1 };
static int n = Sentinel;

আকর্ষণীয় পদ্ধতির, তবে আমি আশঙ্কা করছি যে প্রাথমিক পর্যায়ে static int n = sentinel;সি তে সম্পূর্ণরূপে উপযুক্ত নয় কারণ sentinelসি স্ট্যান্ডার্ড অনুযায়ী ধ্রুবক প্রকাশ নয়। এটা তোলে C ++ কাজ করে, এবং এটি MSVC 2017 সি মোডে কিন্তু জিসিসি এবং ঝনঝন বর্তমান সংস্করণের সাথে প্রনয়ন, কিন্তু আপনি সম্ভবত লেখা উচিত static int n = -1;দেখতে godbolt.org/z/8pEMnz
chqrlie

1
নিবন্ধন করুন এটি নির্দেশ করার জন্য আপনাকে ধন্যবাদ। আকর্ষণীয় সংকলক আচরণ। : আমি এই প্রশ্নে এই সম্পর্কে জিজ্ঞাসা করেছি stackoverflow.com/q/61037093/2805305
bolov

5

এই সমস্যাটি চুক্তিবদ্ধ সমাধানগুলির জন্য প্রার্থনা করে।

এখানে এমন একটি যা এক বা দুটি intযুক্তি গ্রহণ করে একটি ফাংশন ব্যবহার করে :

  • যদি প্রথম যুক্তিটি ইতিবাচক হয় তবে এটি সেই মানটির জন্য অভিব্যক্তিটি গণনা করে
  • যদি প্রথম যুক্তিটি নেতিবাচক হয় তবে এটি অবশ্যই দ্বিতীয় তর্ক দ্বারা অনুসরণ করা উচিত এবং পূর্ববর্তী পদক্ষেপের জন্য পুনরাবৃত্তি করে গণনার একটি একক পদক্ষেপ সম্পাদন করবে।
  • এটি ব্যবহার করে <stdarg.h>যা সম্ভবত বা অনুমোদিত নয়।

কোডটি এখানে:

#include <math.h>
#include <stdarg.h>

double rec_sqrt_series(int n, ...) {
    if (n < 0) {
        va_arg ap;
        va_start(ap, n);
        int m = va_arg(ap, int);
        va_end(ap);
        if (m > -n) {
            return 0.0;
        } else {
            return sqrt(m + rec_sqrt_series(n, m + 1));
        }
    } else {
        return rec_sqrt_series(-n, 1);
    }
}

এখানে একটি একক ফাংশন সহ আরও একটি সমাধান রয়েছে যা কেবলমাত্র ব্যবহার <math.h>করেই, তবে নিয়মগুলিকে অন্যভাবে গালি দেওয়া হয়: ম্যাক্রো ব্যবহার করে।

#include <math.h>

#define rec_sqrt_series(n)  (rec_sqrt_series)(n, 1)
double (rec_sqrt_series)(int n, int m) {
    if (m > n) {
        return 0.0;
    } else {
        return sqrt(m + (rec_sqrt_series)(n, m + 1));
    }
}

তবুও আরেকটি, পুনরাবৃত্তির সাথে কঠোরভাবে কথা বলছে , তবে একক পুনরাবৃত্তির স্তর এবং অন্য কোনও কৌশল নয়। হিসাবে এরিক মন্তব্য, এটি একটি ব্যবহার forলুপ যা ওপি এর সীমাবদ্ধতা অধীনে অবৈধ হতে পারে:

double rec_sqrt_series(int n) {
    if (n > 0) {
        return rec_sqrt_series(-n);
    } else {
        double x = 0.0;
        for (int i = -n; i > 0; i--) {
            x = sqrt(i + x);
        }
        return x;
    }
}

হ্যাঁ আমি অনুমান করি যে কাজ করে। সমস্ত সহায়তার জন্য আপনাকে অনেক ধন্যবাদ
রোনেন ডিভোরকিন

সর্বশেষে double rec_sqrt_series(int n), আইএমও, পুনরাবৃত্তি পতাকা হিসাবে সাইনটি ব্যবহার করে ওপির লক্ষ্যগুলি পূরণ করে। (আমি ড্রপ চাই elseহিসাবে প্রয়োজন না returnহয় if।)
পুনর্বহাল মনিকা - chux

1
@ chux-ReinstateMonica: ফেলে দেওয়া elseঅবশ্যই সম্ভব তবে আমি ifফলপ্রসূ উভয় শাখার প্রতিসাম্য তৈরি করতে চাই , ফলস্বরূপ প্রোগ্রামিং শৈলীর সাজসজ্জা করি।
chqrlie

@ chux-ReinstateMonica: আমি আশা করি নিয়োগের প্রয়োজনটি কেবল "পুনরাবৃত্তি" এর পুনরাবৃত্তিকে হ্রাস করে।
এরিক পোস্টপিসিল

@ এরিকপোস্টপিসিল: হ্যাঁ, আমিও একই চিন্তা করেছিলাম, কিন্তু ওপি থেকে প্রতিক্রিয়া পাইনি।
chqrlie

0

এখানে অন্য পদ্ধতির।

এটি int32 বিট হওয়ার উপর নির্ভর করে । ধারণাটি হ'ল উপরের 32 বিটটি 64 বিটের ব্যবহার intকরা

1) দেখুন কলটি কোনও পুনরাবৃত্ত কল ছিল (বা "বাইরের" থেকে একটি কল)

2) পুনরাবৃত্তির সময় উপরের 32 বিটগুলিতে লক্ষ্য মানটি সংরক্ষণ করুন

// Calling convention:
// when calling this function 'n' must be a positive 32 bit integer value
// If 'n' is zero or less than zero the function have undefined behavior
double rec_sqrt_series(uint64_t n)
{
  if ((n >> 32) == 0)
  {
    // Not called by a recursive call
    // so start the recursion
    return rec_sqrt_series((n << 32) + 1);
  }

  // Called by a recursive call

  uint64_t rn = n & 0xffffffffU;

  if (rn == (n >> 32)) return sqrt(rn);      // Done - target reached

  return sqrt (rn + rec_sqrt_series(n+1));   // Do the recursive call
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.