पायथन में अधिकतम पुनरावृत्ति गहराई क्या है, और इसे कैसे बढ़ाया जाए?


421

मेरे पास यहाँ यह पुनरावर्ती कार्य है:

def recursive_function(n, sum):
    if n < 1:
        return sum
    else:
        return recursive_function(n-1, sum+n)

c = 998
print(recursive_function(c, 0))

यह काम करता है n=997, तो यह बस टूट जाता है और बाहर थूकता है RecursionError: maximum recursion depth exceeded in comparison। यह सिर्फ एक ढेर अतिप्रवाह है? क्या इसके आसपास पाने का कोई तरीका है?



9
संस्मरण आपके कार्य को गति दे सकता है और स्टैक के आकार को बढ़ाने के बजाय पहले से गणना किए गए मानों को समाप्त करके अपनी प्रभावी पुनरावर्ती गहराई को बढ़ा सकता है।
1947

2
पुनरावृत्ति सीमा आमतौर पर 1000 है।
बोरिस

1
@tonix दुभाषिया एक स्टैक फ्रेम ( line <n>, in <module>स्टैक निशान में) जोड़ता है और इस कोड के लिए 2 स्टैक फ्रेम लेता है n=1(क्योंकि आधार मामला है n < 1, इसलिए इसके लिए n=1अभी भी पुनरावृत्ति होती है)। और मुझे लगता है कि पुनरावृत्ति सीमा समावेशी नहीं है, क्योंकि यह "त्रुटि है जब आप 1000 हिट करते हैं" नहीं "त्रुटि यदि आप 1000 (1001) से अधिक है"। 997 + 2यह 1000 से कम है इसलिए यह काम 998 + 2नहीं करता है क्योंकि यह सीमा को हिट करता है।
बोरिस

1
@tonix नहीं। recursive_function(997)काम करता है, यह टूट जाता है 998। जब आप कॉल करते हैं तो recursive_function(998)यह 999 स्टैक फ्रेम का उपयोग करता है और 1 फ्रेम दुभाषिया द्वारा जोड़ा जाता है (क्योंकि आपका कोड हमेशा चलाया जाता है जैसे कि यह शीर्ष स्तर मॉड्यूल का हिस्सा है), जो इसे 1000 की सीमा तक हिट करता है।
बोरिस

जवाबों:


469

यह एक स्टैक ओवरफ्लो के खिलाफ एक गार्ड है, हाँ। पायथन (या बल्कि, सीपीथॉन कार्यान्वयन) पूंछ पुनरावृत्ति का अनुकूलन नहीं करता है, और बेलगाम पुनरावृत्ति स्टैफ़्लोज़ का कारण बनता है। आप के साथ पुनरावर्तन सीमा की जांच कर सकते हैं और पुनरावृत्ति सीमा को sys.getrecursionlimitबदल सकते हैं sys.setrecursionlimit, लेकिन ऐसा करना खतरनाक है - मानक सीमा थोड़ी रूढ़िवादी है, लेकिन पायथन स्टैकफ्रेम काफी बड़ा हो सकता है।

पायथन एक कार्यात्मक भाषा नहीं है और पूंछ की पुनरावृत्ति एक विशेष रूप से कुशल तकनीक नहीं है। एल्गोरिथ्म को पुनरावृत्त करना, यदि संभव हो तो, आम तौर पर एक बेहतर विचार है।


4
मेरे अनुभव से, आपको sysऔर resourceमॉड्यूल दोनों में सीमा बढ़ाने की आवश्यकता है : stackoverflow.com/a/16248113/205521
थॉमस अहले

3
इसे एक पुनरावृत्त संस्करण में बदलने के लिए एक रणनीति के रूप में, एक टेल कॉल ऑप्टिमाइज़ेशन डेकोरेटर का इस्तेमाल किया जा सकता है
jfs

3
आप अपनी OS ऊपरी सीमा का पता लगाने के लिए svn.python.org/projects/python/trunk/Tools/scripts/… का उपयोग कर सकते हैं
Ullullu

8
स्रोत में रुचि रखने वालों के लिए, डिफ़ॉल्ट पुनरावर्तन सीमा 1000 hg.python.org/cpython/file/tip/Python/ceval.c#l691 पर सेट है और इसे hg.python.org/cpython पर API का उपयोग करके बदला जा सकता है। /file/tip/Python/sysmodule.c#l643 जो बदले में नए मान की सीमा hg.python.org/cpython/file/tip/Python/sval.c#l703
Pramod

16
टेल रीसर्शन प्रोग्रामिंग भाषा में इसके लिए अनुकूलित एक पूरी तरह से कुशल तकनीक है। सही प्रकार की समस्या के लिए, यह एक पुनरावृत्त कार्यान्वयन के लिए बहुत अधिक स्पष्ट हो सकता है। इसका उत्तर शायद "पायथन में विशेष रूप से" है, लेकिन ऐसा नहीं है जो यह कहता है
पीटर आर

135

लगता है कि आपको बस एक उच्च पुनरावृत्ति गहराई सेट करने की आवश्यकता है :

import sys
sys.setrecursionlimit(1500)

मेरे मामले में मैं आधार मामले में रिटर्न स्टेटमेंट भूल गया और यह 1000 से अधिक हो गया। पायथन ने इस अपवाद को फेंकना शुरू कर दिया और मैं आश्चर्यचकित था, क्योंकि मैं नहीं के बारे में निश्चित था। इसे चलाने के लिए बनाने के लिए जा रहा ढेर।
vijayraj34

यदि आपका प्रोग्राम पुनरावृत्ति में प्रवेश कर रहा है और आप एक ही पाठ के पृष्ठ और पृष्ठ नहीं होना चाहते हैं, तो आप sys.setrecursionlimit (50) या एक छोटी राशि उपयोगी है। मुझे खराब पुनरावर्ती कोड डीबग करते समय यह बहुत मददगार लगा।
peawormsworth

56

यह एक ढेर अतिप्रवाह से बचने के लिए है। पायथन दुभाषिया अनंत पुनरावृत्ति से बचने में आपकी मदद करने के लिए पुनरावृत्ति की गहराई को सीमित करता है, जिसके परिणामस्वरूप स्टैक ओवरफ्लो होता है। पुनरावर्तन सीमा बढ़ाएँ ( sys.setrecursionlimit) या पुनरावर्ती के बिना अपने कोड को फिर से लिखना।

से अजगर प्रलेखन :

sys.getrecursionlimit()

पुनरावृत्ति सीमा के वर्तमान मूल्य को वापस करें, पायथन दुभाषिया स्टैक की अधिकतम गहराई। यह सीमा अनंत पुनरावृत्ति को सी स्टैक के अतिप्रवाह और दुर्घटनाग्रस्त पायथन को रोकने से रोकती है। इसके द्वारा सेट किया जा सकता है setrecursionlimit()


मेरे एनाकोंडा x64 पर, विंडोज पर 3.5 पायथन, डिफ़ॉल्ट सीमा 1000 है।
गिलियूम शेवेलियर

30

यदि आपको अक्सर पुनरावर्तन सीमा को बदलने की आवश्यकता होती है (उदाहरण के लिए प्रोग्रामिंग पहेलियाँ हल करते समय) तो आप इस तरह से एक साधारण संदर्भ प्रबंधक को परिभाषित कर सकते हैं :

import sys

class recursionlimit:
    def __init__(self, limit):
        self.limit = limit
        self.old_limit = sys.getrecursionlimit()

    def __enter__(self):
        sys.setrecursionlimit(self.limit)

    def __exit__(self, type, value, tb):
        sys.setrecursionlimit(self.old_limit)

फिर एक कस्टम सीमा के साथ एक फ़ंक्शन को कॉल करने के लिए जो आप कर सकते हैं:

with recursionlimit(1500):
    print(fib(1000, 0))

withविवरण के मुख्य भाग से बाहर निकलने पर पुनरावृत्ति सीमा को डिफ़ॉल्ट मान पर पुनर्स्थापित किया जाएगा।


आप इस प्रक्रिया की पुनरावृत्ति सीमाresource भी चाहते हैं । इसके बिना, आपको एक सेगमेंटेशन फ़ॉल्ट मिलेगा और यदि आप setrecursionlimitबहुत अधिक हैं तो पूरी पायथन प्रक्रिया क्रैश हो जाएगी और नई सीमा (लगभग 8 मेगाबाइट के स्टैक फ्रेम का उपयोग करने की कोशिश करें, जो ऊपर दिए गए साधारण फ़ंक्शन के साथ ~ 30,000 स्टैक फ्रेम पर अनुवाद करता है) मेरा लेपटोप)।
बोरिस

16

एक भाषा का उपयोग करें जो पूंछ-कॉल अनुकूलन की गारंटी देता है। या पुनरावृति का उपयोग करें। वैकल्पिक रूप से, सज्जाकारों के साथ प्यारा हो जाओ ।


36
बल्कि बच्चे को नहाने के पानी से बाहर फेंकना चाहिए।
रसेल बोरोगोव

3
@ रसेल: मेरे द्वारा प्रस्तावित विकल्पों में से केवल एक ही इसकी सलाह देता है।
मार्सेलो कैंटोस

"सज्जाकारों के साथ प्यारा हो जाओ" बिल्कुल एक विकल्प नहीं है।
श्री बी

@ Mr.B जब तक आप से अधिक की आवश्यकता ulimit -sढेर फ्रेम की, हाँ यह है stackoverflow.com/a/50120316
बोरिस

14

resource.setrlimit स्टैक का आकार बढ़ाने और सेगफ़ॉल्ट को रोकने के लिए भी उपयोग किया जाना चाहिए

लिनक्स कर्नेल प्रक्रियाओं के ढेर को सीमित करता है

अजगर दुभाषिया के ढेर पर स्थानीय चर संग्रहीत करता है, और इसलिए पुनरावृत्ति दुभाषिया का ढेर स्थान लेता है।

यदि पायथन इंटरप्रेटर स्टैक सीमा से अधिक जाने की कोशिश करता है, तो लिनक्स कर्नेल इसे विभाजन दोष बनाता है।

स्टैक सीमा का आकार getrlimitऔर setrlimitसिस्टम कॉल के साथ नियंत्रित किया जाता है ।

पायथन resourceमॉड्यूल के माध्यम से उन सिस्टम कॉल तक पहुंच प्रदान करता है ।

import resource
import sys

print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print

# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)

def f(i):
    print i
    sys.stdout.flush()
    f(i + 1)
f(0)

निश्चित रूप से, यदि आप अल्टिमेट को बढ़ाते रहते हैं, तो आपकी रैम बाहर निकल जाएगी, जो या तो आपके कंप्यूटर को स्वैप पागलपन के कारण आपके कंप्यूटर को धीमा कर देगा, या ओम् किलर के माध्यम से पायथन को मार देगा।

बैश से, आप स्टैक लिमिट (केबी में) के साथ देख और सेट कर सकते हैं:

ulimit -s
ulimit -s 10000

मेरे लिए डिफ़ॉल्ट मान 8Mb है।

यह सभी देखें:

उबंटू 16.10, पायथन 2.7.12 पर परीक्षण किया गया।


1
स्टैक क्लैश रिमेडियेशन के rlimit_stackबाद सेट करने का प्रयास विफलता या संबंधित समस्याओं का कारण हो सकता है। Red Hat अंक 1463241
jww

प्रोफेसर टिम रफगार्डन के माध्य (विशाल) डेटासेट पर कोसाराजू के एल्गोरिथ्म के कार्यान्वयन में मदद करने के लिए मैंने (पायथन संसाधन भाग) इसका उपयोग किया। मेरे कार्यान्वयन ने छोटे सेटों पर काम किया, निश्चित रूप से एक बड़े डेटासेट के साथ समस्या पुनरावृत्ति / स्टैक सीमा थी ... या यह था? खैर, हाँ यह था! धन्यवाद!
नीलो

9

मुझे लगता है कि यह एक पुराना सवाल है, लेकिन पढ़ने वालों के लिए, मैं इस तरह की समस्याओं के लिए पुनरावृत्ति का उपयोग करने के खिलाफ सिफारिश करूंगा - सूचियां बहुत तेज हैं और पूरी तरह से पुनरावृत्ति से बचें। मैं इसे इस प्रकार लागू करूंगा:

def fibonacci(n):
    f = [0,1,1]
    for i in xrange(3,n):
        f.append(f[i-1] + f[i-2])
    return 'The %.0fth fibonacci number is: %.0f' % (n,f[-1])

(X + में n + 1 का उपयोग करें यदि आप 1 के बजाय 0 से अपने रिट्रेसमेंट अनुक्रम को गिनना शुरू करते हैं)


13
जब आप O (1) का उपयोग कर सकते हैं तो O (n) स्थान का उपयोग क्यों करें?
जानूस ट्रॉल्सन

11
बस के मामले में O (n) स्थान टिप्पणी भ्रामक थी: एक सूची का उपयोग न करें। सूची सभी मूल्यों को तब रखेगी जब आपको सभी की आवश्यकता होगी nth मूल्य। एक सरल एल्गोरिदम यह होगा कि अंतिम दो फ़ॉरेस्ट संख्याओं को रखें और उन्हें तब तक जोड़ें जब तक आप अपनी ज़रूरत के अनुसार न प्राप्त कर लें। बेहतर एल्गोरिदम भी हैं।
Milimetric

3
@ मैथाइम: xrangeबस कहा जाता है range, पाइथन 3 में
एरिक ओ लेबिगॉट

1
@ मुझे इस बारे में पता है
मैथाइम

7
@ मैथाइम मैं इन टिप्पणियों को पढ़ने वालों के लिए स्पष्ट कर रहा था।
एरिक ओ लेबिगॉट 9

9

निश्चित रूप से फाइबोनैचि संख्याओं की गणना ओ (एन) में बिनेट सूत्र को लागू करके की जा सकती है:

from math import floor, sqrt

def fib(n):                                                     
    return int(floor(((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5))+0.5))

टिप्पणीकारों के रूप में यह O (1) नहीं है, लेकिन O (n) के कारण है 2**n। इसके अलावा एक अंतर यह है कि आपको केवल एक मूल्य मिलता है, जबकि पुनरावृत्ति के साथ आपको Fibonacci(n)उस मूल्य तक के सभी मूल्य मिलते हैं ।


8
अजगर में लंबे समय तक अधिकतम आकार नहीं होता है।
पिपरी

8
यह ध्यान देने योग्य है कि यह nफ़्लोटिंग पॉइंट इंप्रेशन के कारण बड़े के लिए विफल हो जाता है - बीच का अंतर (1+sqrt(5))**nऔर (1+sqrt(5))**(n+1)1 ulp से कम हो जाता है, इसलिए आपको गलत परिणाम प्राप्त होने लगते हैं।

2
NumPy में वास्तव में कोई बड़ा पूर्णांक नहीं हैं ...
Eric O Lebigot

@ मेगो क्या? यह बीच का अंतर है (1+sqrt(5))**nऔर ((1+sqrt(5))**n)+1यह 1 ulp से कम हो जाता है! (छोटे टाइपो) इसके अलावा, {@} rwst यह O (1) नहीं है! गणना 2**nमें कम से कम O (n) समय लगता है।
user202729

3
@ user202729 कि सच नहीं, की गणना 2**nहै प्रभावी रूप से ओ (लॉग (एन)) का उपयोग करते हुए बराबरी द्वारा Exponentiattion
सैम

6

मेरे पास त्रुटि "मैक्स रिकर्सन डेप्थ पार हो गई" जैसा ही मुद्दा था। मुझे पता चला कि जिस निर्देशिका के साथ मैं लूपिंग कर रहा था उसमें एक भ्रष्ट फ़ाइल द्वारा त्रुटि को ट्रिगर किया जा रहा था os.walk। यदि आपको इस समस्या को हल करने में समस्या है और आप फ़ाइल पथ के साथ काम कर रहे हैं, तो इसे कम करना सुनिश्चित करें, क्योंकि यह एक भ्रष्ट फ़ाइल हो सकती है।


2
ओपी अपना कोड देता है, और उसका प्रयोग इच्छानुसार प्रजनन योग्य होता है। इसमें भ्रष्ट फाइलें शामिल नहीं हैं।
टी। वेरोन

5
आप ठीक कह रहे हैं, लेकिन मेरा जवाब ओपी की ओर नहीं है, क्योंकि यह चार साल पहले था। मेरा उत्तर उन लोगों की मदद करने का लक्ष्य है जो भ्रष्ट फ़ाइलों के कारण अप्रत्यक्ष रूप से MRD त्रुटियों के साथ हैं - क्योंकि यह पहले खोज परिणामों में से एक है। इसने वोट देने के बाद से किसी की मदद की। डाउन वोट के लिए धन्यवाद।
टायलर

2
यह केवल एक चीज थी जो मैंने कहीं भी पाया जब अपने मुद्दे की खोज की जो एक भ्रष्ट फ़ाइल में "अधिकतम पुनरावृत्ति गहराई" ट्रेसबैक से जुड़ी। धन्यवाद!
जेफ

5

यदि आप केवल कुछ फाइबोनैचि संख्याएँ प्राप्त करना चाहते हैं, तो आप मैट्रिक्स विधि का उपयोग कर सकते हैं।

from numpy import matrix

def fib(n):
    return (matrix('0 1; 1 1', dtype='object') ** n).item(1)

यह तेज है क्योंकि तेजी से घातांक एल्गोरिथ्म का उपयोग किया जाता है। आपको ओ (लॉग एन) में जवाब मिलता है। और यह Binet के सूत्र से बेहतर है क्योंकि यह केवल पूर्णांक का उपयोग करता है। लेकिन अगर आप सभी फाइबोनैचि संख्याओं को n तक चाहते हैं, तो इसे मेमोरिसिएशन द्वारा करना बेहतर है।


अफसोस की बात है कि आप अधिकांश प्रतिस्पर्धी प्रोग्रामिंग जजों में सुन्न का उपयोग नहीं कर सकते। लेकिन हां सर, आपका समाधान मेरा पसंदीदा है। मैंने कुछ समस्याओं के लिए मैट्रिक्स सॉल्यूशन का उपयोग किया है। यह सबसे अच्छा समाधान है जब आपको एक बहुत बड़ी रिट्रेसमेंट संख्या की आवश्यकता होती है और आप मापांक का उपयोग नहीं कर सकते हैं। यदि आपको एक मापांक का उपयोग करने की अनुमति दी जाती है, तो यह करने के लिए बेहतर तरीका है।
मेंटैग्स

4

जनरेटर का उपयोग करें?

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fibs = fib() #seems to be the only way to get the following line to work is to
             #assign the infinite generator to a variable

f = [fibs.next() for x in xrange(1001)]

for num in f:
        print num

फ़ाइब के ऊपर () फ़ंक्शन से अनुकूलित किया गया: http://intermediatepythonista.com/python-generators


1
एक चर को जनरेटर सौंपने का कारण [fibs().next() for ...]यह है कि हर बार एक नया जनरेटर होगा।
19123 में tox123

3

जैसा कि @alex ने सुझाव दिया था , आप पुनरावर्ती के बजाय इसे क्रमिक रूप से करने के लिए एक जनरेटर फ़ंक्शन का उपयोग कर सकते हैं ।

यहाँ आपके प्रश्न में कोड के बराबर है:

def fib(n):
    def fibseq(n):
        """ Iteratively return the first n Fibonacci numbers, starting from 0. """
        a, b = 0, 1
        for _ in xrange(n):
            yield a
            a, b = b, a + b

    return sum(v for v in fibseq(n))

print format(fib(100000), ',d')  # -> no recursion depth error

2

कई लोग सलाह देते हैं कि पुनरावृत्ति सीमा बढ़ाना एक अच्छा समाधान है, हालांकि ऐसा नहीं है क्योंकि हमेशा सीमा रहेगी। इसके बजाय एक पुनरावृत्त समाधान का उपयोग करें।

def fib(n):
    a,b = 1,1
    for i in range(n-1):
        a,b = b,a+b
    return a
print fib(5)

1

मैं आपको फाइबोनैचि की गणना करने के लिए संस्मरण का उपयोग करने के लिए एक उदाहरण देना चाहता था क्योंकि यह आपको प्रतिसाद का उपयोग करके बड़ी संख्या में गणना करने की अनुमति देगा:

cache = {}
def fib_dp(n):
    if n in cache:
        return cache[n]
    if n == 0: return 0
    elif n == 1: return 1
    else:
        value = fib_dp(n-1) + fib_dp(n-2)
    cache[n] = value
    return value

print(fib_dp(998))

यह अभी भी पुनरावर्ती है, लेकिन एक सरल हैशटेबल का उपयोग करता है जो उन्हें फिर से करने के बजाय पहले से गणना किए गए फाइबोनैचि संख्याओं के पुन: उपयोग की अनुमति देता है।


1
import sys
sys.setrecursionlimit(1500)

def fib(n, sum):
    if n < 1:
        return sum
    else:
        return fib(n-1, sum+n)

c = 998
print(fib(c, 0))

1
ऐसा ही जवाब कई बार दिया गया है। कृपया इसे हटा दें।
ZF007

0

हम @lru_cacheडेकोरेटर और setrecursionlimit()विधि का उपयोग कर सकते हैं :

import sys
from functools import lru_cache

sys.setrecursionlimit(15000)


@lru_cache(128)
def fib(n: int) -> int:
    if n == 0:
        return 0
    if n == 1:
        return 1

    return fib(n - 2) + fib(n - 1)


print(fib(14000))

उत्पादन

3002468761178461090995494179715025648692747937490792943468375429502230242942284835863402333575216217865811638730389352239181342307756720414619391217798542575996541081060501905302157019002614964717310808809478675602711440361241500732699145834377856326394037071666274321657305320804055307021019793251762830816701587386994888032362232198219843549865275880699612359275125243457132496772854886508703396643365042454333009802006384286859581649296390803003232654898464561589234445139863242606285711591746222880807391057211912655818499798720987302540712067959840802106849776547522247429904618357394771725653253559346195282601285019169360207355179223814857106405285007997547692546378757062999581657867188420995770650565521377874333085963123444258953052751461206977615079511435862879678439081175536265576977106865074099512897235100538241196445815568291377846656352979228098911566675956525644182645608178603837172227838896725425605719942300037650526231486881066037397866942013838296769284745527778439272995067231492069369130289154753132313883294398593507873555667211005422003204156154859031529462152953119957597195735953686798871131148255050140450845034240095305094449911578598539658855704158240221809528010179414493499583473568873253067921639513996596738275817909624857593693291980841303291145613566466575233283651420134915764961372875933822262953420444548349180436583183291944875599477240814774580187144637965487250578134990402443365677985388481961492444981994523034245619781853365476552719460960795929666883665704293897310201276011658074359194189359660792496027472226428571547971602259808697441435358578480589837766911684200275636889192254762678512597000452676191374475932796663842865744658264924913771676415404179920096074751516422872997665425047457428327276230059296132722787915300105002019006293320082955378715908263653377755031155794063450515731009402407584683132870206376994025920790298591144213659942668622062191441346200098342943955169522532574271644954360217472458521489671859465232568419404182043966092211744372699797375966048010775453444600153524772238401414789562651410289808994960533132759532092895779406940925252906166612153699850759933762897947175972147868784008320247586210378556711332739463277940255289047962323306946068381887446046387745247925675240182981190836264964640612069909458682443392729946084099312047752966806439331403663934969942958022237945205992581178803606156982034385347182766573351768749665172549908638337611953199808161937885366709285043276595726484068138091188914698151703122773726725261370542355162118164302728812259192476428938730724109825922331973256105091200551566581350508061922762910078528219869913214146575557249199263634241165352226570749618907050553115468306669184485910269806225894530809823102279231750061652042560772530576713148647858705369649642907780603247428680176236527220826640665659902650188140474762163503557640566711903907798932853656216227739411210513756695569391593763704981001125

स्रोत

फंतासी lru_cache


0

हम गतिशील प्रोग्रामिंग बॉटम अप अप्रोच का भी उपयोग कर सकते हैं

def fib_bottom_up(n):

    bottom_up = [None] * (n+1)
    bottom_up[0] = 1
    bottom_up[1] = 1

    for i in range(2, n+1):
        bottom_up[i] = bottom_up[i-1] + bottom_up[i-2]

    return bottom_up[n]

print(fib_bottom_up(20000))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.