Convert this function from recursive to iterative - python

def g(n):
"""Return the value of G(n), computed recursively.
>>> g(1)
1
>>> g(2)
2
>>> g(3)
3
>>> g(4)
10
>>> g(5)
22
"""
if n<=3:
return n
else:
return g(n-1)+2*g(n-2)+3*g(n-3)
How do I convert this to an iterative function? Until now, I didn't realize that writing a recursive function is sometimes easier than writing an iterative one. The reason why it's so hard I think is because I don't know what operation the function is doing. In the recursive one, it's not obvious what's going on.
I want to write an iterative definition, and I know I need to use a while loop, but each time I try to write one either I add additional parameters to g_iter(n) (when there should only be one), or I make a recursive call. Can someone at least start me off on the right path? You don't have to give me a complete solution.
FYI: We have not learned of the all too common "stack" I'm seeing on all these pages. I would prefer to stay away from this.
def g_iter(n):
"""Return the value of G(n), computed iteratively.
>>> g_iter(1)
1
>>> g_iter(2)
2
>>> g_iter(3)
3
>>> g_iter(4)
10
>>> g_iter(5)
22
"""
"*** YOUR CODE HERE ***"

def g(n):
if n <= 3:
return n
a, b, c = 1, 2, 3
for i in range(n - 3):
a, b, c = b, c, c + 2 * b + 3 * a
return c
UPDATE response to comment, without using for loop.
def g(n):
if n <= 3:
return n
a, b, c = 1, 2, 3
while n > 3:
a, b, c = b, c, c + 2 * b + 3 * a
n -= 1
return c

Related

How to find exponent of pow(a,b,c) in python

pow(a,x,c) operator in python returns (a**x)%c . If I have values of a, c, and the result of this operation, how can I find the value of x?
Additionally, this is all the information I have
pow(a,x,c) = pow(d,e,c)
Where I know the value of a,c,d, and e.
These numbers are very large (a = 814779647738427315424653119, d = 3, e = 40137673778629769409284441239, c = 1223334444555556666667777777) so I can not just compute these values directly.
I'm aware of the Carmichael's lambda function that can be used to solve for a, but I am not sure if and/or how this applies to solve for x.
Any help will be appreciated.
As #user2357112 says in the comments, this is the discrete logarithm problem, which is computationally very difficult for large c, and no fast general solution is known.
However, for small c there are still some things you can do. Given that a and c are coprime, there is an exponent k < c such that a^k = 1 mod c, after which the powers repeat. Let b = a^x. So, if you brute force it by calculating all powers of a until you get b, you'll have to loop at most c times:
def do_log(a, b, c):
x = 1
p = a
while p != b and p != 1:
x += 1
p *= a
p %= c
if p == b:
return x
else:
return None # no such x
If you run this calculation multiple times with the same a, you can do even better.
# a, c constant
p_to_x = {1: 0}
x = 1
p = a
while p != 1:
p_to_x[p] = x
x += 1
p *= a
p %= c
def do_log_a_c(b):
return p_to_x[b]
Here a cache is made in a loop running at most c times and the cache is accessed in the log function.

Looping through an interval in either direction

Suppose you want to loop through all integers between two bounds a and b (inclusive), but don't know in advance how a compares to b. Expected behavior:
def run(a, b):
if a < b:
for i in range(a, b + 1):
print i,
elif a > b:
for i in range(a, b - 1, -1):
print i,
else:
print a
print
run(3, 6)
run(6, 3)
run(5, 5)
Result:
3 4 5 6
6 5 4 3
5
Is there a more elegant solution? The following is more concise, but fails when a == b:
def run(a, b):
for i in range(a, b + cmp(b, a), cmp(b, a)):
print i,
print
run(3, 6)
run(6, 3)
run(5, 5)
Result:
3 4 5 6
6 5 4 3
(...)
ValueError: range() step argument must not be zero
This will work for all cases:
def run(a, b):
"""Iterate from a to b (inclusive)."""
step = -1 if b < a else 1
for x in xrange(a, b + step, step):
yield x
The insight that led me to this formulation was that step and the adjustment to b were the same in both of your cases; once you have an inclusive end you don't need to special-case a == b. Note that I've written it as a generator so that it doesn't just print the results, which makes it more use when you need to integrate it with other code:
>>> list(run(3, 6))
[3, 4, 5, 6]
>>> list(run(6, 3))
[6, 5, 4, 3]
>>> list(run(5, 5))
[5]
Using generator delegation in Python 3.3+ (see PEP-380), this becomes even neater:
def run(a, b):
"""Iterate from a to b (inclusive)."""
step = -1 if b < a else 1
yield from range(a, b + step, step)
You almost got it yourself:
def run(a, b):
for i in range(a, b + (cmp(b, a) or 1), cmp(b, a) or 1):
print i,
print
works just fine... when cmp(b, a) evaluates to 0 (when they are equal), it defaults to 1, although I'd definitely consider Jon's answer more elegant, you were on the right track! I make extensive use of python's logical or when doing comparisons like this:
(func() or default) is very useful for any function that returns a zero that you want to overwrite. Python evaluates it as False or True and returns default.
range(min((a,b)), max((a,b))+1)

Making Range Function Act Over Given Values in Python

I would like to know if there is a way to make the range function act only over some given values.
I'm trying to write some code for Problem 2 of Project Euler where I must find the sum of the even-valued terms of the Fibonacci sequence whose values do not exceed 4,000,000.
My code at the moment looks like this:
#Fibonacci Even Sum
even_sum = 0
def fib(n):
a, b = 1,2
while a < n:
print (a)
a, b = b, a + b
print ()
return a
for i in range(fib(4000000)):
if i % 2 == 0:
even_sum = i + even_sum
print (even_sum)
The problem seems to be that my code adds up all the even numbers up to 3524578, not just the even Fibonacci numbers. How can I change this?
Many thanks !
You should use a generator function, range() does not suit your problem. You can convert your fib function to a generator by giving yield a inside the while loop, that would make the function keep spitting out fibonacci numbers till n and you can find sum like that.
Example of generator -
>>> def fib(n):
... a, b = 1,2
... while a < n:
... yield a
... a, b = b, a+b
...
>>>
>>>
>>>
>>> for i in fib(200):
... print(i)
...
1
2
3
5
8
13
21
34
55
89
144
you can make similar changes to your function.
Code would look like -
even_sum = 0
def fib(n):
a, b = 1,2
while a < n:
print (a)
a, b = b, a + b
yield a
for i in fib(4000000):
if i % 2 == 0:
even_sum = i + even_sum
print (even_sum)

Python: Usage of Variables and their difference ("a, b = 0, 1" VS "a = 0", "b = 1") [duplicate]

This question already has answers here:
Python - Difference between variable value declaration on Fibonacci function
(4 answers)
Closed 8 years ago.
I was looking at the Python Manual and found this snippet for a Fibonacci-Number generator:
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while b < n:
print(b, end=' ')
a, b = b, a+b
print()
The output is dependent on n and returns a valid Fibonacci sequence.
If you remodel this to use the variables "a" and "b" seperately like so:
def fib(n): # write Fibonacci series up to n
a = 0
b = 1
while b < n:
print(b, end=' ')
a = b
b = a+b
print()
then it will print a number sequence that increments by the power of 2 (e.g. 1, 2, 4, 8, 16 and so on).
So I was wondering why that happens? What is the actual difference between the two uses of variables?
Doing:
a, b = b, a+b
is equivalent to:
temp = a
a = b
b += temp
It lets you simultaneously do two calculations without the need of an intermediate/temporary variable.
The difference is that in your second piece of code, when you do the second line b = a+b, you have already modifed a in the previous line which is not the same as the first piece of code.
Examples
>>> a = 2
>>> b = 3
>>> a,b
2 3
>>> a,b = b,a
>>> a,b
3 2
On the other hand, if you use the second approach shown in your question:
>>> a = 2
>>> b = 3
>>> a,b
2 3
>>> a = b
>>> b = a
>>> a,b
3 3
In
a, b = b, a+b
the right-hand expressions are evaluated first, and their results are assigned to a and b. This is similar to the following:
_new_a = b
_new_b = a+b
a = _new_a
b = _new_b
On the other hand, in
a = b
b = a+b
you are modifying a before adding it to b. This is equivalent to
a, b = b, b+b
which explains where the powers of two are coming from.

Error in for loop. (Finding three integers)

So, our teacher gave us an assignment to find three integers a, b c. They are in all between 0 and 450 using Python.
a = c + 11 if b is even
a = 2c-129 if b is odd
b = ac mod 2377
c = (∑(b-7k) from k = 0 too a-1) +142 (Edited. I wrote it wrong. Was -149)
I tired my code that looks like this: (Still a newbie. I guess a lot of my code is wrong)
for a, b, c in range(0, 450):
if b % 2 == 0:
a = c + 11
else:
a = 2 * c - 129
b = (a * c) % 2377
c = sum(b - 7 * k for k in range(0, a - 1))
but I get the error:
for a, b, c in range(0, 450):
TypeError: 'int' object is not iterable
What am I doing wrong and how can I make it check every number between 0 and 450?
The answers by Nick T and Eric hopefully helped you solve your issue with iterating over values of a, b, and c. I would like to also point out that the way you're approaching this problem isn't going to work. What's the point of iterating over various values of a if you're going to re-assign a to something anyway at each iteration of the loop? And likewise for b and c. A better approach involves checking that any given triple (a, b, c) satisfies the conditions given in the assignment. For example:
from itertools import product, tee
def test(a, b, c):
flags = {'a': False,
'b': False,
'c': False}
if (b % 2 == 0 and a == c+11) or (b % 2 == 1 and a == 2*c-129):
flags['a'] = True
if b == (a * c) % 2377:
flags['b'] = True
if c == sum(b - 7*k for k in range(a-1)) - 149:
flags['c'] = True
return all(flags.values()) # True if zero flags are False
def run_tests():
# iterate over all combinations of a=0..450, b=0..450, c=0..450
for a, b, c in product(*tee(range(451), 3)):
if test(a, b, c):
return (a, b, c)
print(run_tests())
NOTE: This is a slow solution. One that does fewer loops, like in glglgl's answer, or Duncan's comment, is obviously favorable. This is really more for illustrative purposes than anything.
import itertools
for b, c in itertools.product(*[range(450)]*2):
if b % 2 == 0:
a = c + 11
else:
a = 2 * c - 129
derived_b = (a * c) % 2377
derived_c = sum(b - 7 * k for k in range(0, a - 1))
if derived_b == b and derived_c == c:
print a, b, c
You need to nest the loops to brute-force it like you are attempting:
for a in range(451): # range(450) excludes 450
for b in range(451):
for c in range(451):
...
It's very obviously O(n3), but if you want a quick and dirty answer, I guess it'll work—only 91 million loops, worst case.
The stuff with [0, 450] is just as a hint.
In fact, your variables are coupled together. You can immediately eliminate at least one loop directly:
for b in range(0, 451):
for c in range(0, 451):
if b % 2: # odd
a = 2 * c - 129
else:
a = c + 11
if b != (a * c) % 2377: continue # test failed
if c != sum(b - 7 * k for k in range(a)): continue # test failed as well
print a, b, c
should do the job.
I won't post full code (after all, it is homework), but you can eliminate two of the outer loops. This is easiest if you iterate over c.
You code should then look something like:
for c in range(451):
# calculate a assuming b is even
# calculate b
# if b is even and a and b are in range:
# calculate what c should be and compare against what it is
# calculate a assuming b is odd
# calculate b
# if b is odd and a and b are in range:
# calculate what c should be and compare against what it is
Extra credit for eliminating the duplication of the code to calculate c
a = c + 11 if b is even
a = 2c-129 if b is odd
b = ac mod 2377
c = (∑(b-7k) from k = 0 to a-1) +142
This gives you a strong relation between all 3 numbers
Given a value a, there are 2 values c (a-11 or (a+129)/2), which in turn give 2 values for b (ac mod 2377 for both values of c, conditioned on the oddity of the result for b), which in turn gets applied in the formula for validating c.
The overall complexity for this is o(n^2) because of the formula to compute c.
Here is an implementation example:
for a in xrange(451):
c_even = a - 11
b = (a*c_even) % 2377
if b % 2 == 0:
c = sum(b - 7 * k for k in range(a)) + 142
if c == c_even:
print (a, b, c)
break
c_odd = (a+129)/2
b = (a*c_odd) % 2377
if b % 2 == 1:
c = sum(b - 7 * k for k in range(a)) + 142
if c == c_odd:
print (a, b, c)
break

Categories