सी में एक नेस्टेड रूट की गणना


9

मुझे केवल पुनरावृत्ति का उपयोग करके निम्नलिखित नेस्टेड रूट अभिव्यक्ति की गणना करने के लिए कहा गया था ।

यहां छवि विवरण दर्ज करें

मैंने उस काम के नीचे कोड लिखा था, लेकिन उन्होंने हमें केवल एक फ़ंक्शन और 1 इनपुट का उपयोग करने की अनुमति दी nऔर 2 का उपयोग नहीं किया। क्या कोई मुझे इस कोड को एक फ़ंक्शन में बदलने में मदद कर सकता है जो अभिव्यक्ति की गणना करेगा? खिचड़ी भाषा किसी भी पुस्तकालय के कार्यों को छोड़कर उपयोग नहीं करती है <math.h>

n = 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.
Kaz

1
@chqrlieforyellowblockquotes Twisied। @pastaleg बेकार पुनरावृत्ति के बारे में कैसे? 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: हाँ, नियमों का एक सरल दुरुपयोग।
चकरली

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। यह सही परिणाम पैदा करता है क्योंकि श्रृंखला केवल कुछ दर्जन पुनरावृत्तियों के बाद फ्लोटिंग-पॉइंट प्रारूप में बदलना बंद कर देती है - गहरी संख्याओं की वर्गमूल जड़ें इतनी पतला हो जाती हैं कि उनका कोई प्रभाव नहीं होता है। इसलिए फ़ंक्शन में 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-बिट ints :)
chqrlie

1
@chqrlieforyellowblockquotes: नाह, यही कारण है कि Rअलग है, इसलिए इसे ट्यून किया जा सकता है। n32 तक पहुंचने से पहले , IEEE-754 बाइनरी 64 के लिए रिटर्न वैल्यू बदलना बंद हो जाता है, और इससे पहले कि यह 256 तक पहुंचता है, रिटर्न वैल्यू के लिए फॉर्मूला फॉर्मूला बदलना बंद हो जाता है double। इसलिए मैं एक वैकल्पिक संस्करण पर विचार कर रहा हूं जो ऊपर दिए गए क्लैंप इनपुट को बदल देता है R, लेकिन इसे साइन बिट का उपयोग करने की आवश्यकता है, और मैं अभी भी इस पर काम कर रहा हूं।
एरिक पोस्टपिसिल

कर रहे हैं अन्य जोड़ी कार्यों आप उपयोग कर सकते हैं, लेकिन तुम्हारा के रूप में सरल रूप में कोई नहीं। उनका मुख्य लाभ आम तौर पर यह है कि वे मनमानी परिशुद्धता के साथ काम करते हैं, लेकिन ओपी ने कभी भी आवश्यकता के रूप में उल्लेख नहीं किया है।
रूड हेलडरमैन 20

@chqrlieforyellowblockquotes: हो गया। अब nकी चौड़ाई की परवाह किए बिना किसी भी सकारात्मक के लिए सही उत्तर का उत्पादन करता है int
एरिक पोस्टपिसिल

5

गणितीय रूप से सूत्र को बदलने के बिना (मुझे नहीं पता कि यह संभव है), आप वास्तव में सिर्फ एक पैरामीटर का उपयोग नहीं कर सकते हैं, जैसा कि प्रत्येक तत्व के लिए आपको दो informations की आवश्यकता है: वर्तमान चरण और मूल 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
@chqrlieforyellowblockquotes ish इस बारे में बताने के लिए शुक्रिया। दिलचस्प संकलक व्यवहार। मैंने इस प्रश्न में इसके बारे में पूछा है: 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;
    }
}

हाँ जो मुझे लगता है कि काम करता है। सभी मदद के लिए बहुत बहुत धन्यवाद
Ronen Dvorkin

अंतिम double rec_sqrt_series(int n), IMO, पुनरावर्तन ध्वज के रूप में साइन का उपयोग करके ओपी के लक्ष्यों को पूरा करता है। (मैं ड्रॉप होता elseरूप में की जरूरत के रूप में नहीं returnहै if।)
को पुनः स्थापित मोनिका - chux

1
@ chux-ReinstateMonica: ड्रापिंग elseबेशक संभव है लेकिन मैं थोड़े ifसमय के लिए रिटर्निंग की दोनों शाखाओं की समरूपता का परिणाम चाहता हूं , कार्यात्मक प्रोग्रामिंग शैली की तरह।
चक्र्ली

@ chux-ReinstateMonica: मुझे उम्मीद है कि "पुनरावृत्ति केवल" असाइनमेंट की आवश्यकता पुनरावृत्ति को रोकती है।
एरिक पोस्टपिसिल

@ EricPostpischil: हाँ, मैंने ऐसा ही सोचा था, लेकिन ओपी से प्रतिक्रिया नहीं मिली।
22

0

यहाँ एक और दृष्टिकोण है।

यह int32 बिट्स पर निर्भर करता है । विचार 64 बिट के ऊपरी 32 बिट का उपयोग 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
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.