फाइबोनैचि अनुक्रम के कुशल पाइथोनिक जनरेटर
इस क्रम में सबसे कम पायथनिक पीढ़ी प्राप्त करने की कोशिश करते हुए मुझे यह सवाल मिला (बाद में एहसास हुआ कि मैंने पायथन एन्हांसमेंट प्रस्ताव में एक समान देखा था ), और मैंने किसी और को अपने विशिष्ट समाधान के साथ आने पर ध्यान नहीं दिया (हालांकि शीर्ष उत्तर पास हो जाता है, लेकिन अभी भी कम सुरुचिपूर्ण है), इसलिए यहां यह है, पहली पुनरावृत्ति का वर्णन करने वाली टिप्पणियों के साथ, क्योंकि मुझे लगता है कि इससे पाठकों को मदद मिल सकती है:
def fib():
a, b = 0, 1
while True: # First iteration:
yield a # yield 0 to start with and then
a, b = b, a + b # a will now be 1, and b will also be 1, (0 + 1)
और उपयोग:
for index, fibonacci_number in zip(range(10), fib()):
print('{i:3}: {f:3}'.format(i=index, f=fibonacci_number))
प्रिंट:
0: 0
1: 1
2: 1
3: 2
4: 3
5: 5
6: 8
7: 13
8: 21
9: 34
10: 55
(एट्रिब्यूशन उद्देश्यों के लिए, मैंने हाल ही में मॉड्यूल पर पायथन प्रलेखन में एक समान कार्यान्वयन देखा , यहां तक कि चर का उपयोग करते हुए a
और b
, जिसे अब मुझे यह उत्तर लिखने से पहले देखा गया है। लेकिन मुझे लगता है कि यह उत्तर भाषा के बेहतर उपयोग को प्रदर्शित करता है।)
पुनरावर्ती रूप से परिभाषित कार्यान्वयन
पूर्णांक दृश्यों ऑनलाइन इनसाइक्लोपीडिया ऑफ़ फाइबोनैचि अनुक्रम रिकर्सिवली को परिभाषित करता है के रूप में
एफ (एन) = एफ (एन -1) + एफ (एन -2) के साथ एफ (0) = 0 और एफ (1) 1
पायथन में इस पुनरावर्ती रूप से स्पष्ट रूप से परिभाषित किया जा सकता है:
def rec_fib(n):
'''inefficient recursive function as defined, returns Fibonacci number'''
if n > 1:
return rec_fib(n-1) + rec_fib(n-2)
return n
लेकिन गणितीय परिभाषा का यह सटीक प्रतिनिधित्व 30 से अधिक की संख्या के लिए अविश्वसनीय रूप से अक्षम है, क्योंकि गणना की जा रही प्रत्येक संख्या को इसके नीचे के प्रत्येक अंक के लिए भी गणना करना होगा। आप निम्न का उपयोग करके दिखा सकते हैं कि यह कितना धीमा है:
for i in range(40):
print(i, rec_fib(i))
दक्षता के लिए पुनरावृत्ति को याद किया
गति में सुधार करने के लिए इसे याद किया जा सकता है (यह उदाहरण इस तथ्य का लाभ उठाता है कि डिफ़ॉल्ट कीवर्ड तर्क एक ही वस्तु है जिसे हर बार फ़ंक्शन कहा जाता है, लेकिन आम तौर पर आप इस कारण से एक पारस्परिक डिफ़ॉल्ट तर्क का उपयोग नहीं करेंगे):
def mem_fib(n, _cache={}):
'''efficiently memoized recursive function, returns a Fibonacci number'''
if n in _cache:
return _cache[n]
elif n > 1:
return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
return n
आपको पता चल जाएगा कि संस्मरणित संस्करण बहुत तेज़ है, और इससे पहले कि आप कॉफ़ी के लिए उठने के बारे में सोच सकें उससे पहले आपकी अधिकतम पुनरावृत्ति गहराई से अधिक हो जाएगी। आप देख सकते हैं कि ऐसा करने से नेत्रहीन कितना तेज है:
for i in range(40):
print(i, mem_fib(i))
(ऐसा लग सकता है कि हम बस नीचे कर सकते हैं, लेकिन यह वास्तव में हमें कैश का लाभ नहीं लेने देता है, क्योंकि यह सेटडेफॉल्ट कहे जाने से पहले खुद को कॉल करता है।)
def mem_fib(n, _cache={}):
'''don't do this'''
if n > 1:
return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
return n
पुनरावर्ती रूप से परिभाषित जनरेटर:
जैसा कि मैं हास्केल सीख रहा हूं, मैं हास्केल में इस कार्यान्वयन पर आया हूं:
fib@(0:tfib) = 0:1: zipWith (+) fib tfib
इस समय मुझे लगता है कि मैं पायथन में सबसे करीब आ सकता हूं:
from itertools import tee
def fib():
yield 0
yield 1
# tee required, else with two fib()'s algorithm becomes quadratic
f, tf = tee(fib())
next(tf)
for a, b in zip(f, tf):
yield a + b
यह इसे प्रदर्शित करता है:
[f for _, f in zip(range(999), fib())]
यह केवल पुनरावृत्ति सीमा तक जा सकता है, हालांकि। आमतौर पर, 1000, जबकि हास्केल संस्करण 100 से लाखों तक जा सकता है, हालांकि यह ऐसा करने के लिए मेरे लैपटॉप की सभी 8 जीबी मेमोरी का उपयोग करता है:
> length $ take 100000000 fib
100000000
एनटीआर नंबर प्राप्त करने के लिए पुनरावृत्ति का उपभोग करना
एक टिप्पणीकार पूछता है:
Fib () फ़ंक्शन के लिए प्रश्न जो पुनरावृत्ति पर आधारित है: क्या होगा यदि आप nth प्राप्त करना चाहते हैं, उदाहरण के लिए 10 वें फ़ाइब नंबर?
Itertools प्रलेखन के लिए एक नुस्खा है:
from itertools import islice
def nth(iterable, n, default=None):
"Returns the nth item or a default value"
return next(islice(iterable, n, None), default)
और अब:
>>> nth(fib(), 10)
55