Make fibo faster [duplicate] - python

This question already has answers here:
Efficient calculation of Fibonacci series
(33 answers)
Closed 4 years ago.
I need to write a code to give a number and print me the F[number].This code is pretty slow.Any ideas for a faster code?
while True:
n=input()
if n=='END' or n=='end':
break
class Fibonacci:
def fibo(self, n):
if int(n) == 0:
return 0
elif int(n) == 1:
return 1
else:
return self.fibo(int(n)-1) + self.fibo(int(n)-2)
f=Fibonacci()
print(f.fibo(n))

I have written a bit about faster fibonacci in this post, maybe one of them is useful for you? https://sloperium.github.io/calculating-the-last-digits-of-large-fibonacci-numbers.html
Anyway. Your code is very slow because you get exponential running time calling the same subtrees over and over.
You can try a linear solution:
def fib3(n):
if n == 0:
return 0
f1 = 0
f2 = 1
for i in range(n-1):
f1,f2 = f2, f1+f2
return f2

You can use functools memoize to make it store previous values so it doesn't have to recursively call the fibonacci function. The example they list is literally fibonacci

You can use a dict to memoize the function:
class Fibonacci:
memo = {}
def fibo(self, n):
if n in self.memo:
return self.memo[n]
if int(n) == 0:
value = 0
elif int(n) == 1:
value = 1
else:
value = self.fibo(int(n) - 1) + self.fibo(int(n) - 2)
self.memo[n] = value
return value

Use dynamic programming: this prevents it calculating all the way down to 0 and 1 each time:
memory = {0:0, 1:1}
def fibo(n):
if n in memory:
return memory[n]
else:
ans = fibo(int(n)-1) + fibo(int(n)-2)
memory[n] = ans
return ans
Test:
>>> fibo(1000)
43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
This is almost instantaneous.

Don't use a class; you're not gaining anything from it
Don't needlessly redefine your class each loop
Convert from str to int once, up front, rather than over and over
(If not required by assignment) Use iterative solution, not recursive
With just #1-3, you'd end up with:
def fibo(n): # Using plain function, defined once outside loop
if n < 2:
return n
return fib(n - 1) + fibo(n - 2)
while True:
n = input()
if n.lower() == 'end':
break
print(fibo(int(n))) # Convert to int only once
If you're not required to use a recursive solution, don't; Fibonacci generation is actually a pretty terrible use for recursion, so redefine the function to:
def fibo(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
which performs O(n) work rather than O(2**n) work. Memoizing could speed up the recursive solution (by decorating fibo with #functools.lru_cache(maxsize=None)), but it's hardly worth the trouble when the iterative solution is just so much faster and requires no cache in the first place.

Related

Changing an iterative function into a recursive one

Consider:
def itr(n):
s = 0
for i in range(0, n+1):
s = s + i * i
return s
This is a simple iterative function that I would like to change into a recursive function.
def rec(n):
import math
if n!=0:
s=n-(2*math.sqrt(n))
if s!=0:
return(s+rec(n))
else:
return(n)
else:
return n
This is my try at doing the said thing, but I cannot quite get it right.
Why does not my solution work? What is the solution?
Use:
def recursive(total, n):
if n == 0:
return total
else:
return recursive(total + n * n, n - 1)
A couple of thoughts:
This can be refactored to using only a single argument, but by supplying both the total and the current iteration count, it is easier to see how to transform the iterative approach to a recursive one.
While this function can be made recursive, it should not be, as there isn't any advantage over the iterative approach.

recursive function to sum of first odd numbers python

I'm trying to convert below code to recursive function but seems i'm quite confusing how could i write below in recursive function. could help me to give some thoughts?
Basically, what I'm generating below is the sum of the first n odd numbers.
def sum_odd_n(n):
total=0
j=2*n-1
i=1
if i>j:
return 1
else:
total =((j+1)/2)**2
i+=2
return total
> >>> sum_odd_n(5)
> 25.0
> >>> sum_odd_n(4)
> 16.0
> >>> sum_odd_n(1)
> 1.0
This smells somewhat like homework so I'm going to offer some advice instead of a solution.
Recursion is about expressing a problem in terms of itself.
Suppose you know the sum of the odd numbers from N to N - 2.
Can you write the total sum in terms of this sum and the function itself (or a related helper function)?
Recursive functions have at least one base case and at least one recursive call. Here are some hints:
def f(n):
# Base case - for which
# n do we already know the answer
# and can return it without
# more function calls? (Clearly,
# this must also terminate any
# recursive sequence.)
if n == ???:
return ???
# Otherwise, lets say we know the answer
# to f(n - 1) and assign it to
# the variable, 'rest'
rest = f(n - 1)
# What do we need to do with 'rest'
# to return the complete result
return rest + ???
Fill out the question marks and you'll have the answer.
Try:
def sum_of_odd(n):
if n>0:
x=(n*2)-1
return x+sum_of_odd(n-1)
else:
return 0
The answer of this:
sum_of_odd(5)
will be:
25
Try :
def sum_odd_n(n):
if n>0:
if n==1:
return 1
else:
return 2*n-1 + sum_odd_n(n-1)

exponential sum using recursion.python

I need to write a function using recursion that accepts the following variables:
n: int
x: real
and returns the exponential sum function:
I can't use loops at all, only recursion.
I started by writing two recursive functions for sum and factorial but when I tried to combine the two of them I got the error message:
TypeError: 'int' object is not iterable
I don't quite understand what it means because I didn't use loops, only recursion. Here is my code:
def sum_exp(n):
if n == 0:
return 0
return n + sum(n - 1)
def factorial(n):
if n == 0:
return 1
else:
return n*factorial(n-1)
def exp_n_x(n, x):
if n == 0:
return 1
else:
return sum_exp(x*(1/factorial(n)))
print(exp_n_x(10, 10))
I would love to get some help with this. Thanks a lot in advance.
you've made a typo in:
def sum_exp(n):
if n == 0:
return 0
return n + sum(n - 1)
^^^
where you use the global function sum() which takes an iterable and returns the sum of its elements. Thus:
>>> sum(42)
TypeError: 'int' object is not iterable
whereas
>>> sum([42])
42
so your fix is straightforward:
def sum_exp(n):
if n == 0:
return 0
return n + sum_exp(n - 1)
N.B.: This answer is only meant to fix your issue with the TypeError, and get you going to the next error you'll hit, which is an infinite recursion. As an advice you should double check your stop condition and recursion step.

How to run down a list with recursion?

At first, I had to do it without recursion (just by looping which is pretty easy).
Now I have to do it with recursion, but I am not allowed to use any loop.
I guess I have to run down the list with recursion, but I don't quite understand what should be my base, or the reduction...
def long_strings_rec(strings, N):
'''
strings - a list of strings
N - an integer
Returns all strings in 'strings' of length bigger then 'N'
(This function is recursive and does not use loops)
'''
# Your code for question #2 (second function) starts here
# Your code for question #2 (second function) ends here
Any ideas? Can I have maybe an example of how to use recursion to take actions on lists indexes?
I used the helper function to do that, like #7stud suggested:
def helper (strings, K, results):
if len(strings) == 0:
return 0
elif len(strings[0]) > K:
results.append(strings[0])
strings.pop(0)
else:
strings.pop(0)
helper(strings, K, results)
return results
def long_strings_rec (strings, N):
'''
strings - a list of strings
N - an integer
Returns all strings in 'strings' of length bigger then 'N'
(This function is recursive and does not use loops)
'''
# Your code for question #2 (second function) starts here
return helper(strings, N, [])
# Your code for question #2 (second function) ends here
Worked like a charm. Hope it's not buggy.
Here's an example of how to use an accumulator:
def sum(nums):
return helper(nums, 0) #0 is the initial value for the accumulator
def helper(nums, total): #total is the accumulator
if len(nums) == 0:
return total
else:
num = nums.pop()
return helper(nums, total+num)
print sum([1, 2, 3])
--output:--
6
Basically, you redefine sum() so that it takes an additional accumulator parameter variable, then have sum() call the new function.
See if you can apply those principles to your problem.
As bjorn pointed out in the comments, you could do it like this too:
def mysum(nums, total=0):
if len(nums) == 0:
return total
else:
num = nums.pop()
return sum(nums, total+num)
print mysum([1, 2, 3])
--output:--
6

Recursion depth error in simple Python program

I am new to programming, and was trying to solve this problem on Project Euler using basic Python.
Essentially, I tried to use recursion based on the largest value chosen at every stage, and using a list to maintain possible options for future choices.
The code is short and is given below:
def func(n,l):
if n<0:
return 0
if l==[1] or n==0:
return 1
else:
j=0
while l != []:
j=j+func(n-l[0],l)
del l[0]
return j
print func(200,[200,100,50,20,10,5,2,1])
For instance, if we have
func(5,[5,2,1])
the recursion splits it into
func(0,[5,2,1]) + func(3,[2,1]) + func(4,[1])
But the code never seems to go through. Either it says that there is a list-index-out-of-range error, or a maximum-recursion-depth error (even for very small toy instances). I am unable to find the mistake. Any help will be much appreciated.
In Python lists are passed into functions by reference, but not by value. The simplest fix for your program is changing recursive call to func(n - l[0], l[:]). In this way list will be passed by value.
One thing you're failing to take into account is that the following:
j=j+func(n-l[0],l)
doesn't make a copy of l.
Therefore all recursive invocations of func operate on the same list. When the innermost invocation deletes the last element of l and returns, its caller will attempt to del l[0] and will get an IndexError.
At each recursion, make the following 2 decisions:
Take the first coin (say f) from available coin types, then check if we can made (n-f) from those coins. This results in a sub-problem func(n - f, l)
Ignore the first coin type, and check if we can make n from the remaining coin types. This results in a sub-problem func(n, l[1:])
The total number of combinations should be the sum of the two sub-problems. So the code goes:
def func(n, l):
if n == 0:
return 1
if n < 0 or len(l) == 0:
return 0
if l == [1] or n == 0:
return 1
return func(n - l[0], l) + func(n, l[1:])
Each recursion a copy of l is made by l[1:]. This can be omitted by pop element before next recursion and restore with append afterwards.
def func(n, l):
if n == 0:
return 1
if n < 0 or len(l) == 0:
return 0
if l == [1] or n == 0:
return 1
full = func(n - l[-1], l)
last = l.pop()
partial = func(n, l)
l.append(last)
return full + partial

Categories

Resources