Mystery recursive function python - python

def mystery_code(n):
return mystery_recursive(n, n-1)
def mystery_recursive(a, b):
if b<=0:
return 0
else:
c=mystery_recursive(a,b-1)
if a%b==0:
c+=b
return c
Could someone please help me understand what this code does?

It computes the sum of proper divisors of n.
If you step through the code you'll see it calls, e.g., mystery_recursive(5, 4) and then recursively mystery_recursive(5, 3), mystery_recursive(5, 2), mystery_recursive(5, 1), mystery_recursive(5, 0). It'll then return 0 because b <= 0.
In each of these calls, it assigns the result of a call to c and if a % b == 0 (i.e., a can be divided by b) then it adds b to c. So you'll end up with a sum of the proper divisors of n.

As already told by Simeon Visser the above code computes the sum of proper divisors of n.
if your function call is:
mystery_code(12)
then it will call the mystery recursive function (mystery_recursive(a, b)) in your code as:
mystery_recursive(12, 11)
Once the recursive function started to execute it will keep on calling itself until the condition b<=0 satisfies. In this case mystery_recursive(12, 0) will return a value of '0' to the variable 'c' to its called function mystery_recursive(12, 1). Then, beginning with the above mystery function (mystery_recursive(12, 1)) the 'c' value will be computed and returned to their respective calling functions of the same until the called function mystery_recursive(12, 11).
Output in this case: 16

Perhaps it helps to convert this recursive function to an interative version
def mystery_recursive(a, b):
c = 0
while True:
if b <= 0:
return c
if a % b == 0:
c += b
b -= 1
It's still a bit clumsy, so try to convert it to a sum generator expression
def mystery_recursive(a, b):
return sum(b for b in range(b, 0, -1) if a % b == 0)
You can even roll that back into mystery_code
def mystery_code(n):
return sum(b for b in range(n - 1, 0, -1) if n % b == 0)

Related

How to find numbers which GCD equal to 1 and those numbers are less than given in python

I am trying to write code which gives you numbers which are less than given or entered number , and their GCD equal to 1 . I wrote this code but I don't know if works or why not . For example I chose number 6. array will be like [1,2,3,4,5]. And my point is to filter numbers that GCD equals to 1. So it will be [1,5]. And their amount is two.
a is input number and b is list numbers that are less than entered one and not equal to zero . And then print it .
a = int(input("enter number \n"))
b = list(range(1,a))
print (b)
Then I convert list to array
for i in range(1, len(b)):
b[i] = int(b[i])
and then this
r = a % b[i]
q = int ( a / b[i])
while(r!=0):
a = b[i]
b[i] = r
q = int ( a / b[i])
r = a - (b[i] * q)
print ( a , b[i], r )
break
I am beginner .
A few comments about your code:
You should always encapsulate code like this in a function; write a function find_coprimes which takes an argument n and returns the list you want;
In order to test the correctness of your function, write a reference function find_coprimes_ref which does the same thing, but uses library functions to make sure there is no error; this will teach you to look for relevant library functions, and you can compare the results of the two functions;
The initial loop for i in range(1, len(b)): b[i] = int(b[i]) is wrong for two reasons; 1) It has no effect, as b is already a list of integers. 2) Lists are 0-indexed, so a correct iterations on every element of b would be for i in range(0, len(b)): or simply for i in range(len(b)):;
Your code has two nested loops: a while-loop executing repeatedly inside a for-loop; whenever there are nested loops like this, you must make sure that variables are reinitialised the way you intend them to at the beginning of the outer loop; in your case, variable a is modified inside the while-loop, and as a result, its value is wrong at the beginning of the next iteration of the for-loop.
The break statement at the end of the while-loop makes no sense; in general, break statements only make sense if they are encapsulated in an if conditional, and they act as a substitute for the loop condition; but it's always possible to write loops without using break at all and I recommend you forget about break entirely.
After performing the gcd calculation using q and r, your code is missing something to tell it whether or not to keep b[i] or not in the final result;
For integer division in python, it is better to use // rather than int(... / ...).
Code
import math
def find_coprimes_ref(n):
return [x for x in range(1,n) if math.gcd(x,n) == 1]
def find_coprimes(n):
result = []
for x in range(1, n):
a = n
b = x
r = a % b
q = a // b
while (r > 1):
a = b
b = r
q = a // b
r = a - b * q
if (r == 1):
result.append(x)
return result
# TESTING
for n in range(1, 31):
coprimes_ref = find_coprimes_ref(n)
coprimes = find_coprimes(n)
if coprimes_ref != coprimes:
print(n, coprimes_ref, coprimes)
Note how my code never modifies n or x in the loop; instead, I make copies called a and b and modify the copies.
Encapsulating even further
Note how function find_coprimes_ref is so much easier to read than function find_coprimes? This is not just because we used library function math.gcd. It's because library function math.gcd is a cleanly-encapsulated function with a name that explains clearly what it does. Your code contains a while loop inside a for loop and it's a bit hard to keep track of every variable and everything that is going on and not lost track of our sub-objective and overall objective.
To make your function both easier to read, easier to code and easier to debug, You should encapsulate the gcd calculation inside a function called gcd:
def gcd(a, b):
r = a % b
q = a // b
while (r > 1):
a = b
b = r
q = a // b
r = a - b * q
return r
def find_coprimes(n):
result = []
for x in range(1, n):
if gcd(a, b) == 1:
result.append(x)
return result
# TESTING GCD
for b in range(1, 31):
for a in range(b, 31):
r1 = math.gcd(a, b)
r2 = gcd(a, b)
if r1 != r2:
print(a, b, r1, r2)
# TESTING FIND_COPRIMES
for n in range(1, 31):
coprimes_ref = find_coprimes_ref(n)
coprimes = find_coprimes(n)
if coprimes_ref != coprimes:
print(n, coprimes_ref, coprimes)
There are two reasons why the code is easier to debug now:
The logic for gcd and for find_coprimes is cleanly separated, which means you can reason about gcd clearly without any risk of messing up the list and the other variables used in find_coprimes;
You can test separately your function gcd and your function find_coprimes; and if something doesn't work correctly, you'll know more precisely where to look for the issue rather than just thinking "well, something is wrong somewhere in the code but I have no idea where".
There are a few errors in your code like, break inside while loop. I have refactored your code and also added inbuilt math.gcd function to compare results.
import math
def math_inbuilt_gcd(a, b):
gcd_one = []
for x in b:
if math.gcd(x, a) == 1:
gcd_one.append(x)
print("gcd_one_math_fun:", gcd_one)
def gcd_my_fun(a, b):
gcd_arr = []
for i in range(len(b)):
x, y = a, b[i] # taking x, y just to make things clear
r = x % y # remainder
q = int(x / y) # quotient
while(r != 0):
x = y
y = r
q = int(x/y)
r = x % y
if y == 1:
gcd_arr.append(b[i])
print("gcd_one_my_fun:", gcd_arr)
a = int(input("Enter number: "))
b = list(range(1, a))
print("b:", b)
math_inbuilt_gcd(a, b)
gcd_my_fun(a, b)
Output:
Enter number: 10
b: [1, 2, 3, 4, 5, 6, 7, 8, 9]
gcd_one_math_fun: [1, 3, 7, 9]
gcd_one_my_fun: [1, 3, 7, 9]

Why is my function so slow for specific values?

Beginner programmer here!
So I'm trying to create functions for tetration using a recursive formula. I use that same function tetrate_F in finding the nth super root of some big number.
In sprRt(a, b), when b gets a tiny bit too high the function seems to slow down by a ton. I find that 2,3 and 5 works for pretty much any value of a. But when b is set to 4 or any other value it just takes so damn long for some reason.
def tetrate_F(a, b):
if b == 0:
return b+1
else:
res = a ** tetrate_F(a, b-1)
return(res)
def sprRt(a, b):
l_head = []
lt0 = []
if b == 1:
print("Undefined")
elif b > 1:
for j in range(0, a+1):
if tetrate_F(j, b) < a:
lt0.append(j)
elif tetrate_F(j, b) > a:
break
val0 = lt0[-1]
lt0.clear()
l_head.append(val0)
print(val0)
sprRt(1234567890, 4)
Like in sprRt(1234567890, 2), I can use 2,3 or even 5 for b and get a result almost immediately but not any other number.
Help will be much appreciated thx!

Python -While loop to recursive [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
How do you convert the code below to recursive ?
def fibonacci(n):
a, b = 0, 1
fibonacci = [0]
while a < n:
fibonacci.append(b)
a, b = b, a+b
print ('The fibonacci sequence is : '+" ".join(map(str,fibonacci)))
so basically I'm trying write a function fibonacci that receives a
number as parameter and computes the fibonacci series up to that number.
I was able to come up with the above iteration method but it has to be recursive.
This is what I have done so far in terms of converting to recursive but it's not giving me the output I need
def fibo(n, a = 0, b = 1, fib = [0]):
if a < n:
fib.append(b)
a, b = b, a + b
return fib
return fibo(n, a, b, fib)
how about this ?:
def fibonacci(n, a=0, b=1):
if a >= n : return [a]
return [a] + fibonacci(n,b,a+b)
[EDIT] Here's how it works:
The function progressively builds an array by adding one element [a] to the result of the next call to itself.
The first line allows it to stop when the target is reached. Without it, the second line of the function would keep calling itself and there would never be a result coming back from the recursion.
Because the parameters of a function are local to each call, the value of a and b in the second call are different from the previous ones.
If we follow the logic for fibonacci(7), we get:
1) fibonacci(n=7, a=0, b=1) ==> will return [0] + fibonacci(7,1,1).
2) fibonacci(n=7, a=1, b=1) ==> will return [1] + fibonacci(7,1,2).
3) fibonacci(n=7, a=1, b=2) ==> will return [1] + fibonacci(7,2,3).
4) fibonacci(n=7, a=2, b=3) ==> will return [2] + fibonacci(7,3,5).
5) fibonacci(n=7, a=3, b=5) ==> will return [3] + fibonacci(7,5,8).
6) fibonacci(n=7, a=5, b=8) ==> will return [5] + fibonacci(7,8,13).
7) fibonacci(n=7, a=8, b=13) ==> 8 >= 7 so the first line returns [8]
At that point there are no more recursive calls (the first line returns without calling the function again) and the return values start coming back up.
7) returns [8]
6) returns [5,8]
5) returns [3,5,8]
4) returns [2,3,5,8]
3) returns [1,2,3,5,8]
2) returns [1,1,2,3,5,8]
1) returns [0,1,1,2,3,5,8]
One way to think about recursive functions is to look only at the incremental work to be done on the result that would be produced by a prior parameter value. Most of the time this part of the logic applies backwards (i.e computing the end result based on a previous one). For example, a factorial can be thought of as the multiplication of a number with the factorial of the previous number.
This gives you the equivalent of the second line.
Once you have that down, all you need to decide is the condition that makes the recursion stop. Usually this corresponds to the smallest/simplest use case. For example, a factorial does not need to recurse when the number is less than 2 so the function can return 1 directly.
This gives you the equivalent of the first line.
As you can see in the above tracing, the function will proceed "forward" but actually ends up waiting for a result from itself (with different parameters) before being able to complete the process. This is how recursive functions work. The final result is typically built when the return values come back up from the stack of multiple self-calls.
Your fibonacci function is a bit trickier than a factorial because the series can only be computed from the original (0,1) values. Unlike the factorial, we don't have enough information to figure out the value of a and b based on the supplied parameter (n).
And, if you'd like to sink you teeth in cryptic code, here's a one line version:
def fibo(n,a=0,b=1):return [a]+fibo(n,b,a+b) if a < n else [a]
The point of a recursive implementation is to organize things like this:
if we're at a base case:
return the result for that base case
else:
call ourselves with a reduced case
possibly modify the result
return the result
For the base case, a < n, what you do should be related to what you do after the while loop in the iterative version. Adding the last value to the accumulator list fib and returning it makes sense. It may or may not be right, but it's at least in the right direction.
But in your recursive case, you're not calling yourself with a reduced case, you're just calling yourself with the exact same arguments. That's obviously going to be an infinite loop. (Well, Python doesn't do tail call elimination, so it's going to be a stack overflow, which shows up as a max recursion exception, but that's no better.)
So, what should you be doing? Something related to what happens inside the original non-recursive while loop. What you were doing there is:
fibonacci.append(b)
a, b = b, a+b
So, the equivalent is:
fib.append(b)
return fibo(n, b, a+b, fib)
Again, that may not be right, but it's in the right direction. So, if you get the idea, you should be able to carry on from there to debugging the full function.
I think that Dash's answer is correct, modulo a couple of colons. The original question ask for the computation, not printing.
I've added a dict to store computed values to speed things up a bit, and this code works for me:
fib = {}
fib[0] = 0
fib[1] = 1
def fibonacci(n):
if n not in fib.keys():
fib[n] = fibonacci(n - 1) + fibonacci(n - 2)
return fib[n]
if __name__=="__main__":
for i in range(10):
print i, fibonacci(i)
Output:
0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
recursion is a functional heritage
Recursion is a concept that comes from functional style. Mixing imperative-style mutations (like append) and reassignments like a, b = b, a + b is a source of much pain and confusion for new programmers
def fibseq (n, a = 0, b = 1, seq = []):
if n == 0:
return seq + [a]
else:
return fibseq (n - 1, b, a + b, seq + [a])
for x in range (10):
print (fibseq (x))
# [0]
# [0, 1]
# [0, 1, 1]
# [0, 1, 1, 2]
# [0, 1, 1, 2, 3]
# [0, 1, 1, 2, 3, 5]
# [0, 1, 1, 2, 3, 5, 8]
# [0, 1, 1, 2, 3, 5, 8, 13]
# [0, 1, 1, 2, 3, 5, 8, 13, 21]
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
def fibonacci(n):
if n == 0:
return 0
elif n == 1
return 1
else
return fibonacci(n - 1) + fibonacci(n - 2)

What Does This Instruction Do?

I'm new to Python and I don't understand an instruction in the following program:
n = int(input("enter an number : ")
b = 3
p = 1
while n > 0:
n,r = n//2,n%2
p* = b**r
b = b*b
print(p)
I don't understand this statement: n,r = n//2,n%2. What does it do?
Most of the answers are incorrect.
a, b = c, d is a Pythonic concept called "tuple unpacking".
n,r=n//2,n%2 does mean "assign n//2 to n" and "assign n % 2 to r" but n,r is a tuple. In tuple unpacking, all expressions on the RHS are evaluated before assignments. Thus n is not mutated by n//2 before n%2 is evaluated.
Proof of concept for order of operations in tuple unpacking:
a = 1
b = 2
a, b = b, a
if (a==2 and b==1):
print("look ma, I can swap values without needing a temporary variable!")
It is tuple assignment. The each value in the tuple on the left is assigned to the respective value in the tuple on the right. Since the values on the right side are evaluated before any assignment occurs, the value of n before the statement is used. So the line is equivalent to:
tmp = n
n = tmp // 2
r = tmp % 2
It's a parallel assignment:
n, r = n // 2, n % 2
n equals n divided by 2 using integer division, and r equals n modulo 2. It's the same as:
t1 = n // 2
t2 = n % 2
n = t1
r = t2
The values to the right are evaluated, and after that they're assigned, to defer overwriting the original values until we no longer need them.

Iteraction for loop

A function f is defined by the rule that
Write a function f(n) that computes f by an iterative process
I wrote this. and still not getting it right. Please advise how to fix it.
def f(n):
if (n<3):
return n
else:
for x in range (n):
a = f(n-1) + 2*f(n-2) + 3*f(n-3)
return (a)
Simply use a memory cache:
def f(n):
if n < 3:
return n
a,b,c = 0,1,2
for i in range(n-2):
a,b,c = b,c,c+2*b+3*a
return c
In this function we use a to denote f(n-3), b to denote f(n-2) and c for f(n-1), at each iterative step, we calculate f(n) and thus we shift: a becomes b, b becomes c and c obtains the new value. We do this until we have reached the requested n.
So initially we will calculate f(3). In that case, a is f(0)=0, b is f(1)=1, and c is f(2)=2. Now after that iteration, a takes f(1)=1, b takes f(2)=2, and c takes f(3)=f(2)+2×f(1)+3×f(0)=5, and you keep doing that until c has the right n.
This will work faster since in the recursive variant, you call for f(n-2) and f(n-1), but f(n-1) will on his way call for f(n-2) thus introducing duplicated work.
If you want the function to return first n elements, you can use simple dynamic programming with memoization with O(n) space and time:
def F(n):
f = [0]*n
f[:4] = range(4)
for i in range(4, n):
f[i] = f[i-1] + f[i-2] + f[i-3]
return f
print F(20)
# [0, 1, 2, 3, 6, 11, 20, 37, 68, 125, 230, 423, 778, 1431, 2632, 4841, 8904, 16377, 30122, 55403]

Categories

Resources