Calculate the extended gcd using a recursive function in Python - python

I am given the function gcd, which is defined as follows:
def gcd(a, b):
if (0 == a % b):
return b
return gcd(b, a%b)
Now I am asked to write a recursive function gcd2(a,b) that returns a list of three numbers (g, s, t) where g = gcd(a, b) and g = s*a + t*b.
This means that you would enter two values (a and b) into the gcd(a, b) function. The value it returns equals g in the next function.
These same a and b values are then called into gcd2(a, b). The recursive part is then used to find the values for s and t so that g = s*a + t*b.
I am not sure how to approach this because I can't really envision what the "stopping-condition" would be, or what exactly I'd be looping through recursively to actually find s and t. Can anyone help me out?

The key insight is that we can work backwards, finding s and t for each a and b in the recursion. So say we have a = 21 and b = 15. We need to work through each iteration, using several values -- a, b, b % a, and c where a = c * b + a % b. First, let's consider each step of the basic GCD algorithm:
21 = 1 * 15 + 6
15 = 2 * 6 + 3
6 = 2 * 3 + 0 -> end recursion
So our gcd (g) is 3. Once we have that, we determine s and t for 6 and 3. To do so, we begin with g, expressing it in terms of (a, b, s, t = 3, 0, 1, -1):
3 = 1 * 3 + -1 * 0
Now we want to eliminate the 0 term. From the last line of the basic algorithm, we know that 0 = 6 - 2 * 3:
3 = 1 * 3 + -1 * (6 - 2 * 3)
Simplifying, we get
3 = 1 * 3 + -1 * 6 + 2 * 3
3 = 3 * 3 + -1 * 6
Now we swap the terms:
3 = -1 * 6 + 3 * 3
So we have s == -1 and t == 3 for a = 6 and b = 3. So given those values of a and b, gcd2 should return (3, -1, 3).
Now we step back up through the recursion, and we want to eliminate the 3 term. From the next-to-last line of the basic algorithm, we know that 3 = 15 - 2 * 6. Simplifying and swapping again (slowly, so that you can see the steps clearly...):
3 = -1 * 6 + 3 * (15 - 2 * 6)
3 = -1 * 6 + 3 * 15 - 6 * 6
3 = -7 * 6 + 3 * 15
3 = 3 * 15 + -7 * 6
So for this level of recursion, we return (3, 3, -7). Now we want to eliminate the 6 term.
3 = 3 * 15 + -7 * (21 - 1 * 15)
3 = 3 * 15 + 7 * 15 - 7 * 21
3 = 10 * 15 - 7 * 21
3 = -7 * 21 + 10 * 15
And voila, we have calculated s and t for 21 and 15.
So schematically, the recursive function will look like this:
def gcd2(a, b):
if (0 == a % b):
# calculate s and t
return b, s, t
else:
g, s, t = gcd2(b, a % b)
# calculate new_s and new_t
return g, new_s, new_t
Note that for our purposes here, using a slightly different base case simplifies things:
def gcd2(a, b):
if (0 == b):
return a, 1, -1
else:
g, s, t = gcd2(b, a % b)
# calculate new_s and new_t
return g, new_s, new_t

The base case (stopping condition) is:
if a%b == 0:
# a = b*k for the integer k=a/b
# rearranges to b = -1*a + (k+1)*b
# ( g = s*a + t*b )
return (b, -1, a/b+1) # (g, s, t)
However the exercise is to rewrite the recursive part:
g1, s1, t1 = gcd(b, a%b) # where g1 = s1*b + t1*(a%b)
g, s, t = ??? # where g = s*a + t*b
return (g, s, t)
in terms of g1, s1 and t1... which boils down to rewriting a%b in terms of a and b.

"Write a recursive function in Python", at least in CPython, cries for this: be aware of http://docs.python.org/library/sys.html#sys.getrecursionlimit. This is, in my opinion, one of the most important answers to this question. Please do some research on this topic yourself. Also, this thread might be insightful: Python: What is the hard recursion limit for Linux, Mac and Windows?
In conclusion, try to use an iterative instead of a recursive approach in Python whenever possible.

It is based on Euclidian algorithm using better to while loop continued recursion even better and less execution
def gcd(m,n):
#assume m>= n
if m <n:
(m,n) = (n,m)
if (m%n) == 0:
return(n)
else:
diff =m-n
#diff >n ?Possible!
return(gcd(max(n,diff),min(n,diff)))
it can be better by while loop
def gcd(m,n):
if m<n :
(m,n) =(n,m)
while (m%n) !=0:
diff =m-n
(m,n) =(max(n,diff),min(n,diff))
return(n)

Related

How to implement Modular Exponentiation Code

Please I was learning from the book Introduction to algorithm (Chapter 31 page 957) and came across this pseudocode. This pseudocode is how we can implement the modular-exponentiation. The pseudocode is as follows
MODULAR-EXPONENTIATION(a,b,n)
1 c = 0
2 d = 1
3 let <b_k,b_(k-i),....b_0> be the binary representation of b
4 for i = k downto 0
5 c = 2c
6 d = (d.d) mod n
7 if b_i == 1
8 c = c + 1
9 d = (d.a) mod n
10 return d
Then I tried to implement it in python
def modExpn(a,b,n):
c = 0
d = 1
binary_of_b = f'{b:b}'
len_of_b = len(binary_of_b)
for i in range(len_of_b,0,-1):
val = i - 1
c = 2 * c
d = (d * d) % n
if binary_of_b[val] == '1':
c = c + 1
d = (d * a) % n
return d
But when I tried running the function (modExpn) with a = 7,b=560 and n = 561 the output I had was 415 but the right answer is 1. Please where am I going wrong ?
You messed up while translating these parts from the pseudocode into actual code:
3 let <b_k,b_(k-i),....b_0> be the binary representation of b
4 for i = k **downto** 0
These instructions say that you should iterate from the left-most digit (b_k) of the binary representation to the right-most (b_0) since you need to go from k down to 0.
When you transform, for instance, 8 to binary you get "1000", and in Python the index of the left-most digit will be 0 and not len("1000") - 1 as you are doing.
In other words, if you just do:
for bin_digit in binary_of_b:
and later:
if bin_digit == '1':
your code is going to work.

Python - How can I line up the equals sign of all my equations?

Currently in maths class we are working on gcd and I have written a Python script on my NumWorks calculator.
Here is the code I already wrote :
def div(n):
return [x for x in range(1,n+1) if n%x==0]
def pgcd(x,y):
a = x
b = y
while b > 0:
reste = a % b
print(a, "=", a//b, "*", b, "+", a%b)
a,b = b,reste
return "PGCD("+str(x)+";"+str(y)+") = " + str(a)
And it ouputs this :
pgcd(178,52)
178 = 3 * 52 + 22
52 = 2 * 22 + 8
22 = 2 * 8 + 6
8 = 1 * 6 + 2
6 = 3 * 2 + 0
I want it to output that :
178 = 3 * 52 + 22
52 = 2 * 22 + 8
22 = 2 * 8 + 6
8 = 1 * 6 + 2
6 = 3 * 2 + 0
I've read many articles online but I have no idea how to put that into my code.
Thanks in advance.
You can use the rjust string method.
The thing is you need to figure out what is the widest string on the left hand side you will print. Luckily here, it would be the first value.
So I would go with this.
def pgcd(x,y):
a = x
b = y
len_a = len(f"{a}")
while b > 0:
reste = a % b
print(f"{a}".rjust(len_a), "=", a//b, "*", b, "+", a%b)
a,b = b,reste
return "PGCD("+str(x)+";"+str(y)+") = " + str(a)
Should print this.
>>> pgcd(178,52)
178 = 3 * 52 + 22
52 = 2 * 22 + 8
22 = 2 * 8 + 6
8 = 1 * 6 + 2
6 = 3 * 2 + 0
'PGCD(178;52) = 2'
See .format for strings. An example of right justifying would look something like print('{:>6}'.format(42))
You can also use rjust
Use str.format() to achieve this:
'{0: >{width}}'.format(178, 3)
'{0: >{width}}'.format(52, 3)
Will output
178
52
Ok I asked it on a Discord server and they found out so if anyone is having the same problem as me here is the solution (did not put all code for space) :
def pgcd(x,y):
a = x
b = y
maxi = len(str(a))
while b > 0:
reste = a % b
print(" "*(maxi-len(str(a))),a, "=", a//b, "*", b, "+", a%b)
Basically compare to original code we added a maxi variable that has the maximum lenght of my integers, and then if the int is smaller like 8 compare to 178 we add to spaces because the difference of their length is 2.
This explanation is probably not 100% correct but it helps getting an idea.

Using set theory to find the shape area in Python

So I'm given the following diagram:
And I'm being asked to find the area of each polygon given n. The area is basically the sum of all blue squares since each square has an area of 1. So when n = 1, the area is one. When n = 2, the area is 5. Because of the relationship between each polygon, I know that I could knock this down using set theory.
n Area(n)
1 1
2 A(n-1) + (4 * (n-1)) = 5
3 A(n-1) + (4 * (n-1)) = 13
4 A(n-1) + (4 * (n-1)) = 25
5 A(n-1) + (4 * (n-1)) = 41
However, I didn't have as much luck trying to represent this in code:
def shapeArea(n):
prev_output = 0
output = 0
if n == 1:
output = 1
elif n > 1:
for i in range(n):
prev_output = n-1 + (4 * (n-1))
output = prev_output + (4 * (n-1))
return output
For example: For n = 2, I'm getting an output of 9 instead of 5.
You were close :-)
Here are the small fix-ups:
def shapeArea(n):
output = 1
for i in range(1, n):
output += 4 * i
return output
Running this:
for n in range(1, 6):
print(n, shapeArea(n))
Gives this output:
1 1
2 5
3 13
4 25
5 41
of course with Gauss's theorem the code would look like this:
def ShapeArea(n):
return 2*(n**2) - (2*n)+1
In a recursive solution, it is much simple from your logic.
def shape_area(n):
if n == 1:
return 1
return shape_area(n-1) + 4*(n-1)
You can use Gauss' trick to make a closed-form formula:
2*Area(n) =
1 + 4 + 8 + 12 + ... + 4(n-1)
+
1 + 4(n-1) + 4(n-2) + 4(n-3) + ... + 4
--------------------------------------------------
2 + 4n + 4n + 4n + ... + 4n
= (n-1)4n + 2
= 4n^2 - 4n + 2
So Area(n) = 2n2 - 2n + 1
def shape_area(n):
return sum([1] + [4*i for i in range(1, n)])

Karatsuba RecursionError: maximum recursion depth exceeded while calling a Python object

I am trying to implement Karatsuba multiplication on Python.
The inputs are two integers of length power of 2. They are of same length.
def mult(x,y):
if int(x) < 10 and int(y) <10:
return int(x)*int(y)
x_length = len(str(x))//2
y_length = len(str(y))//2
a = str(x)[:x_length]
b = str(x)[x_length:]
c = str(y)[:y_length]
d = str(y)[y_length:]
n = len(a) + len(b)
m = n//2
return 10**n* mult(a,c) + 10**m*(mult(a+b, c+d)-mult(a,c)-mult(b,d)) + mult(b,d)
Running
mult(1234,5678)
This gives the following error:
if int(x) < 10 and int(y) <10:
RecursionError: maximum recursion depth exceeded while calling a Python object
However if I do
def mult(x,y):
if int(x) < 10 and int(y) <10:
return int(x)*int(y)
x_length = len(str(x))//2
y_length = len(str(y))//2
a = str(x)[:x_length]
b = str(x)[x_length:]
c = str(y)[:y_length]
d = str(y)[y_length:]
n = len(a) + len(b)
m = n//2
return 10**n* mult(a,c) + 10**m*(mult(a,d)+mult(b,c)) + mult(b,d)
So I am doing 4 recursions in the last line (i.e. mult(a,c), mult(a,d), mult(b,c), mult(b,d)) rather than 3 as in the above (i.e. mult(a,c), mult(a+b, c+d), mult(b,d)).
Then it turns out ok.
Why is this happening? And how can I do it with only 3 recursions?
a, b, c, d are strings. String addition is concatenation. "1" + "2" is "12". So what is passed to mult(a+b, c+d) is not what you intended to pass.
TL;DR.
First thing first, the recursion is supposed to terminate quickly. Let's see why it doesn't. Add print x, y at the beginning of mult:
def mult(x, y):
print x, y
....
and redirect the output into a file. The result is surprising:
1234 5678
12 56
1 5
12 56
1 5
12 56
1 5
12 56
1 5
....
No wonder the stack overflows. Question is, why we repeat the 12 56 case? Let's add more instrumentation, to find out which recursive call does that:
def mult(x,y,k=-1):
....
print a, b, c, d
ac = mult(a, c, 0)
bd = mult(b, d, 2)
return 10**n* ac + 10**m*(mult(a+b, c+d, 1) - ac - bd) + bd
The results are
-1 : 1234 5678
12 34 56 78
0 : 12 56
1 2 5 6
0 : 1 5
2 : 2 6
1 : 12 56
1 2 5 6
0 : 1 5
2 : 2 6
1 : 12 56
1 2 5 6
0 : 1 5
2 : 2 6
1 : 12 56
You can see that the recursive call marked 1 always gets 12 56. It is the call which computes mult(a + b, c + d). Oh well. All of them a, b, c, d are strings. "1" + "2" is "12". Not exactly what you've meant.
So, make up your mind: are the parameters integer or strings, and treat them accordingly.
Note that in your first code snippet - you are calling your function not thrice, but 5 times:
return 10**n* mult(a,c) + 10**m*(mult(a+b, c+d)-mult(a,c)-mult(b,d)) + mult(b,d)
I can't really say for the rest of your code, but taking a quick look at the Wikipedia entry on Karatsuba, you can decrease your recursion depth by increasing the base number you are using (i.e. from 10 to 100 or 1000). You can change your recursion depth using sys.setrecursionlimit but python stack frames can get quite big, so try to avoid doing so as it may be dangerous.

Fibbonaci-like sequence of last 3 numbers

Is there a non-recursive way I can make a "Fibonacci-like"sequence of the by adding the last 3 numbers?
Here's the recursive way I tried to do it.
def fib3(n):
if n < 3:
return 1
else:
return fib3(n-1) + fib3(n-2) + fib3(n-3)
returns 1+1+1+3+5+9+17...+(n-1) + (n-2) + (n-3)
Any help will be appreciated.
Thanks in advance
Yes, and quite elegantly, with Python's multiple assignment ability:
>>> def fib3(n):
... if n < 3:
... return 1
... a = b = c = 1
... for i in range(3, n):
... # We "shift" a, b, and c to the next values of the sequence.
... a, b, c = b, c, (a + b + c)
... return c
...
>>> fib3(4)
3
>>> fib3(5)
5
>>> fib3(6)
9
>>> fib3(7)
17
And the iterative method would definitely be preferred to the recursive method - as #mu writes, the running time of the recursive implementation is approximately O(3^n), while this method is O(n).
fib_sum to calculate m last integer:
>>> def fib_sum(n,m):
if n < m:
return "n should be greater than m"
a,b,sumit = 0,1,0
for x in range(n):
print b,
if x >= n-m:
sumit += b
a,b = b,a+b
return sumit
>>> fib_sum(3,4)
'n should be greater than m'
>>> fib_sum(3,2)
1 1 2
3
>>> fib_sum(3,1)
1 1 2
2
>>> fib_sum(2,1)
1 1
1
>>> fib_sum(2,2)
1 1
2
>>> fib_sum(7,2)
1 1 2 3 5 8 13
21
>>> fib_sum(7,3)
1 1 2 3 5 8 13
26
>>> fib_sum(8,6)
1 1 2 3 5 8 13 21
52
>>> fib_sum(8,8)
1 1 2 3 5 8 13 21
54
I've arrived late at the party, but: one can easily derive a formula to get the n'th element of any linear recurrence such as the Fibonacci sequence or a generalization of that, without having to compute all the intermediate elements. Say your recurrence is f[n] = a[1] f[n - 1] + a[2] f[n - 2] + ... + a[m] f[n - m]. Suppose that f[n] = (some constant)^n. (This is the kind of "lucky guess" hypothesis that often appears in solutions for differential equations. I don't know how to justify it a priori. It can be justified after the fact by actually finding such a constant.) Then the constant must be a root of the polynomial x^m - a[1] x^(m - 1) - a[2] x^(m - 2) - ... - a[m]. Any linear combination of solutions must also be a solution. You can find the coefficients c[1], ..., c[m] for the linear combination by solving the linear system derived from the first m values (obviously the value of all the later values in the sequence are determined by the first m values).
For the stated recurrence f[n] = f[n - 1] + f[n - 2] + f[n - 3], we have a[1] = a[2] = a[3] = 1 and the roots of x^3 - x^2 - x - 1 are - 0.6063 %i - 0.4196, 0.6063 %i - 0.4196, 1.839, respectively. It is given that the first 3 values are 1, 1, 1. Solving c[1] + c[2] + c[3] = 1, c[1] a[1] + c[2] a[2] + c[3] a[3] = 1, c[1] a[1]^2 + c[2] a[2]^2 + c[3] a[3]^2 = 1 for c[1], c[2], c[3] yields 0.3592 %i + 0.2822, 0.2822 - 0.3592 %i, 0.4356, respectively. (I've written these as approximate, floating point numbers. As roots of polynomials with rational coefficients, these are algebraic numbers, but exact expressions might easily become messy.)
In summary, f[n] = c[1] a[1]^n + c[2] a[2]^n + c[3] a[3]^n, with the stated values for the a's and c's, is a function which gives the n'th element of the recurrence f[n] = f[n - 1] + f[n - 2] + f[n - 3], with f[2] = f[1] = f[0] = 1.
I calculated the a's and c's in Maxima. I can say more about how I did that if there is any interest.

Categories