Converting Iterative Code to Recursive Code Python3 - python-3.x

I'm a beginner programming student and I've been studying recursion functions in Python3 lately. I'm working on a code that basically provides minimum steps requires for a number N to be M undergoing processes of adding 1, divide 2, or multiple 10. I did an iterative function that works well, but as a beginner student of recursive functions I want to be able to convert the code to a recursive code and in this code I was not successful.
I've been reading about this process lately, but as I said it was a very hard implementation for my skills. I know if I want to convert an iterative code I need to use the main loop condition as my base case and the body of the loop as the recursive step and that is all I know.
I would really appreciate it if you could help me to find the base case and the recursive steps of this code. I don't want you to write my code, I want you to help me in reaching my goals.
ITERATIVE CODE
def scape(N, M, steps=0):
if N == M:
return 0
currentoptions = [N]
while True:
if M in currentoptions:
break
thisround = currentoptions[:]
currentoptions = []
for i in thisround:
if (i%2) == 0:
currentoptions.append(i // 2)
currentoptions.append(i + 1)
currentoptions.append(i * 10)
steps += 1
return steps
EXAMPLE
print(scape(8,1))
OUTPUT -> 3
Because 8/2 -> 4/2 -> 2/2 = 1

It is difficult to use pure recursion here (without passing around auxiliary data structures). YOu could do sth along the following lines:
def scape(opts, M, steps=0):
if M in opts:
return steps
opts_ = []
for N in opts:
if not N%2:
opts_.append(N // 2)
opts_.extend((N + 1, N * 10))
return scape(opts_, M, steps+1)
>>> scape([8], 1)
3
Or in order to keep the signature (and not pass around redundant arguments), you could use a recursive helper function:
def scape(N, M):
steps = 0
def helper(opts):
nonlocal steps
if M in opts:
return steps
opts_ = []
for N in opts:
if not N%2:
opts_.append(N // 2)
opts_.extend((N + 1, N * 10))
steps += 1
return helper(opts_)
return helper([N])
>>> scape(8, 1)
3

Related

Conditionally use parts of a nested for loop

I've searched for this answer extensively, but can't seem to find an answer. Therefore, for the first time, I am posting a question here.
I have a function that uses many parameters to perform a calculation. Based on user input, I want to iterate through possible values for some (or all) of the parameters. If I wanted to iterate through all of the parameters, I might do something like this:
for i in range(low1,high1):
for j in range(low2,high2):
for k in range(low3,high3):
for m in range(low4,high4):
doFunction(i, j, k, m)
If I only wanted to iterate the 1st and 4th parameter, I might do this:
for i in range(low1,high1):
for m in range(low4,high4):
doFunction(i, user_input_j, user_input_k, m)
My actual code has almost 15 nested for-loops with 15 different parameters - each of which could be iterable (or not). So, it isn't scalable for me to use what I have and code a unique block of for-loops for each combination of a parameter being iterable or not. If I did that, I'd have 2^15 different blocks of code.
I could do something like this:
if use_static_j == True:
low2 = -999
high2 = -1000
for i in range(low1,high1):
for j in range(low2,high2):
for k in range(low3,high3):
for m in range(low4,high4):
j1 = j if use_static_j==False else user_input_j
doFunction(i, j1, k, m)
I'd just like to know if there is a better way. Perhaps using filter(), map(), or list comprehension... (which I don't have a clear enough understanding of yet)
As suggested in the comments, you could build an array of the parameters and then call the function with each of the values in the array. The easiest way to build the array is using recursion over a list defining the ranges for each parameter. In this code I've assumed a list of tuples consisting of start, stop and scale parameters (so for example the third element in the list produces [3, 2.8, 2.6, 2.4, 2.2]). To use a static value you would use a tuple (static, static+1, 1).
def build_param_array(ranges):
r = ranges[0]
if len(ranges) == 1:
return [[p * r[2]] for p in range(r[0], r[1], -1 if r[1] < r[0] else 1)]
res = []
for p in range(r[0], r[1], -1 if r[1] < r[0] else 1):
pa = build_param_array(ranges[1:])
for a in pa:
res.append([p * r[2]] + a)
return res
# range = (start, stop, scale)
ranges = [(1, 5, 1),
(0, 10, .1),
(15, 10, .2)
]
params = build_param_array(ranges)
for p in params:
doFunction(*p)

saving the result of the recursion iterations

This is a standart permutation function. Im tring to return the list of the lists of the permutations)
Could you help me with storaging the result of the recursion iterations? for example this code returns nonsense. It would be perfect if there was no global variable and rezulting list was inside the func
Thanks!
'''
z=[]
def func(N,M=-1,pref=None):
global z
if M == -1:
M = N
pref = pref or []
if M==0:
z.append(pref)
print(pref)
for i in range(N):
if i not in pref:
pref.append(i)
func(N,M-1,pref)
pref.pop()
func(3)
print(z)
'''
You are passing a list (pref variable in for loop) reference to your function and you are removing a single item from that and that's why you are ending with an empty list z.
Create a new list or copy the list before passing it to the function to avoid this situation.
z = []
def func(N, M=-1, pref=None):
global z
if M == -1:
M = N
pref = pref or []
if M == 0:
z.append(pref)
print(pref)
for i in range(N):
if i not in pref:
pref.append(i)
func(N, M - 1, pref[:])
pref.pop()
func(3)
print(z)
For better understand please read this one. List changes unexpectedly after assignment. How do I clone or copy it to prevent this?
If you want to have some kind of accumulator you must pass it to the recursion function, beware it could be a little nightmare.

Unable to calculate fibonnaci numbers using python

import math
import sys
sys.setrecursionlimit(8000000)
f = {1:2,2:3,3:5}
def fib(n):
if n in f:
return f[n]
if n == 1:
return 2
if n == 2:
return 3
if n == 3:
return 5
val = fib(n-1) + fib(n-2)
if n not in f:
f[n] = val
return f[n]%1000000007
print(fib(4000))
This code fails to complete / command prompt crashes. How can I make this better?
Is there any setting that I need to enable to make this program complete?
Implementing the Fibonacci sequence directly from the mathematical definition is an exercise that illustrates problems with recursive solutions. It leads to an exponential explosion of recursive function calls that even modern computers cannot handle. The biggest problem is that for large values of n, you will calculate fib(1) an exponential number of times.
There are several solutions to this problem:
Use memoization to store values that have already been calculated. Then you look up the calculated value and return it immediately without doing any further calculations. This is a good exercise to learn how memoization works. However, it is still inefficient because you still unnecessarily execute recursive function calls.
Implement an iterative solution. I'm not going to get into the details here. I suggest you do some research to find the iterative solution that will implement fib(n) in linear time instead of exponential time.
Implement the closed formula. Mathematicians have already solved fib(n) as a closed formula. This solution will take constant time no matter how large of an n you use.
use automatic memorization of old vales so that it won't go into infinity loop.use lru_cache as a decorator on your function.
import sys
from functools import lru_cache
sys.setrecursionlimit(8000000)
f = {1:2,2:3,3:5}
#lru_cache(maxsize=None)
def fib(n):
if n in f:
return f[n]
if n == 1:
return 2
if n == 2:
return 3
if n == 3:
return 5
val = fib(n-1) + fib(n-2)
if n not in f:
f[n] = val
return f[n]%1000000007
print(fib(4000))

Memory Error in Python Primality Testing program

def repeated(m, result, a, s, d):
check = True
r = 0
while r <= s - 1:
if result == m - 1:
check = False
return check
result = (result ** 2) % m
r = r + 1
return check
I need to write a primality testing python program to test very large numbers, like at least 100-digit numbers. The code above is part of the code for Miller Rabin deterministic primality test for repeated squaring. It works really slow for large numbers. How can I speed it up? It is for a project. Thanks!
your problem is probably the (result ** 2) % m, use the 3 argument version of pow that do the same but more efficiently because the algorithm use is the Modular exponentiation and that is much better than first doing x**n and then calculate its modulo. this way you are guaranty to never have a number bigger than m while if you do (x**n) % m you can have that x**n is very much bigger than m that may be the cause your problems
Also no need for the check variable and you don't use a.
Also as you go from 0 to s-1, better use range
def repeated(m, result, s, d):
for r in range(s):
if result == m - 1:
return False
result = pow(result, 2, m )
return True
Now for this part of the test
if
you need a, d, s, and n this is how I would do it
def mr_check(n,a,s,d):
result = pow(a,d,n)
if result == 1 :
return False
for r in range(s):
result = pow(result,2,n)
if result == n-1:
return False
return True

11+ digit ints not working

I'm using python 3 for a small extra credit assignment to write an RSA cracker. The teacher has given us a fairly large (large enough to require more than 32 bits) int and the public key. My code works for primes < 32 bits. One of the reasons I chose python 3 is because I heard it can handle arbitrarily large integers. In the python terminal I tested this by doing small things such as 2**35 and factorial(70). This stuff worked fine.
Now that I've written the code, I'm running in to problems with overflow errors etc. Why is it that operations on large numbers seem to work in the terminal but won't work in my actual code? The errors state that they cannot be converted to their C types, so my first guess would be that for some reason the stuff in the python interpreter is not being converter to C types while the coded stuff is. Is there anyway to get this working?
As a first attempt, I tried calculating a list of all primes between 1 and n (the large number). This sort of worked until I realized that the list indexers [ ] only accept ints and explode if the number is higher than int. Also, creating an array that is n in length won't work if n > 2**32. (not to mention the memory this would take up)
Because of this, I switched to using a function I found that could give a very accurate guess as to whether or not a number was prime. These methods are pasted below.
As you can see, I am only doing , *, /, and % operations. All of these seem to work in the interpreter but I get "cannot convert to c-type" errors when used with this code.
def power_mod(a,b,n):
if b < 0:
return 0
elif b == 0:
return 1
elif b % 2 == 0:
return power_mod(a*a, b/2, n) % n
else:
return (a * power_mod(a,b-1,n)) % n
Those last 3 lines are where the cannot convert to c-type appears.
The below function estimates with a very high degree of certainty that a number is prime. As mentioned above, I used this to avoid creating massive arrays.
def rabin_miller(n, tries = 7):
if n == 2:
return True
if n % 2 == 0 or n < 2:
return False
p = primes(tries**2)
if n in p:
return True
s = n - 1
r = 0
while s % 2 == 0:
r = r+1
s = s/2
for i in range(tries):
a = p[i]
if power_mod(a,s,n) == 1:
continue
else:
for j in range(0,r):
if power_mod(a, (2**j)*s, n) == n - 1:
break
else:
return False
continue
return True
Perhaps I should be more specific by pasting the error:
line 19, in power_mod
return (a * power_mod(a,b-1,n)) % n
OverflowError: Python int too large to convert to C double
This is the type of error I get when performing arithmetic. Int errors occur when trying to create incredibly large lists, sets etc
Your problem (I think) is that you are converting to floating point by using the / operator. Change it to // and you should stay in the int domain.
Many C routines still have C int limitations. Do your work using Python routines instead.

Resources