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

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.

Related

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.

Printing reverse Sum of numbers from 1 to n

I am learning python and I am really struggling to figure out how to write this code where I get an input a that is bigger than 1 and the output should look like this:
Sum from 1 to a
Sum from 2 to a
Sum from 3 to a
.....
a
E.g. for 5, the output should be:
15
14
12
9
5
This is what I have so far
a=int(input())
for t in range(a):
b=a*(a+1)/2
b=b-t
print(a+t)
I cant seem to figure out how to subtract it from reverse and how to print each results in the process
The following will work:
a = int(input())
# s = sum(range(1, a+1))
s = a * (a+1) // 2
for t in range(1, a+1):
print(s)
s -= t
Produces for a = 5:
15
14
12
9
5
Instead of only subtracting the counter t, you need to subtract the sum of 1 ... t.
Otherwise your code does not need to be changed, I just added the forcing to int.
a = int(input())
for t in range(a):
b=a*(a+1)//2
c=t*(t+1)//2
b=b-c
print(b)
Output:
15
14
12
9
5

Ulam Spiral (for diagonal numbers) writing program python

I am writing a code the represent the Ulam Spiral Diagonal Numbers and this is the code I typed myself
t = 1
i = 2
H = [1]
while i < 25691 :
for n in range(4):
t += i
H.append(t)
i += 2
print(H)
The number "25691" in the code is the side lenght of the spiral.If it was 7 then the spiral would contain 49 numbers etc.
Here H will give you the all numbers in diagonal. But I wonder is there a much faster way to do this.
For example if I increase the side lenght large amount it really takes forever to calculate the next H.
Code Example:
t = 1
i = 2
H = [1]
for j in range(25000,26000):
while i < j :
for n in range(4):
t += i
H.append(t)
i += 2
For example my computer cannot calculate it so, is there a faster way to do this ?
You dont need to calculate the intermediate values:
Diagonal, horizontal, and vertical lines in the number spiral correspond to polynomials of the form
where b and c are integer constants.
wikipedia
You can find b and c by solving a linear system of equations for two numbers.
17 16 15 14 13
18 5 4 3 12 ..
19 6 1 2 11 28
20 7 8 9 10 27
21 22 23 24 25 26
Eg for the line 1,2,11,28 etc:
f(0) = 4*0*0+0*b+c = 1 => c = 1
f(1) = 4*1*1+1*b+1 = 2 => 5+b = 2 => b = -3
f(2) = 4*2*2+2*(-3)+1 = 11
f(3) = 4*3*3+3*(-3)+1 = 28

Calculate the extended gcd using a recursive function in 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)

Modulo and order of operation in Python

In Zed Shaw's Learn Python the Hard Way (page 15-16), he has an example exercise
100 - 25 * 3 % 4
the result is 97 (try it!)
I cannot see the order of operations that could do this..
100 - 25 = 75
3 % 4 = 0
or (100-25*3) =225 % 4 = ??? but anyhow not 97 I don't think...
A similar example is 3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6 which yields 7
In what order are the operations done?
For the first example: * and % take precedence over -, so we first evaluate 25 * 3 % 4. * and % have the same priority and associativity from left to right, so we evaluate from left to right, starting with 25 * 3. This yields 75. Now we evaluate 75 % 4, yielding 3. Finally, 100 - 3 is 97.
Multiplication >> mod >> subtraction
In [3]: 25 * 3
Out[3]: 75
In [4]: 75 % 4
Out[4]: 3
In [5]: 100 - 3
Out[5]: 97
Multiplication and modulo operator have the same precedence, so you evaluate from left to right for this example.
I figured out the answer to your second question because it was bugging me too--Zac's response is close, but the loss of the result of 1/4 is because of Python 2.X is truncating integer division results. So it's evaluating the modulo operation first, then the division (which since it isn't float, is returned as 0.
3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6
3 + 2 + 1 - 5 + (0) - (0) + 6
6 - 5 + 6
1 + 6
7
Here's how it goes:
'*' and '%' have the same precendence, so evaluate those from left to right.
25*3 = 75
75 % 4 = 3 (4*18 = 72; remainder is 3)
100 - 3 = 97
Q.E.D.
Original problem: 100 - 25 * 3 % 4
Actually, evaluating 25 * 3 and taking 75% of 4 is incorrect, and happened to work out conveniently for this problem.
What the % in python actually is is a modulus operator where x % y gives the remainder of x / y. In this case, what happened was that 75 / 4 is 18, with a remainder of 3, which is why 100 - 3 = 97.
Do not try to multiply the percentages, it's a common mistake.
In the second exampe, %has same order as * so we get 3+2+1-5+4%2-1/4+6=
3+2+1-5+(4%2)-(1/4)+6=1+(4%2)-(1/4)+6
=1+0-(1/4)+6=1-(1/4)+6=0.75+6=6.75 and that is what it says when I try it on the console, so whatever you did you must have done something to round it.
Mathematics isn't my strong point, so yes this question got me as well, for a moment. But hope you find this useful.
75 divided by 4 is 18.75
18 multiplied by 4 is 72 (leaving 3 remaining from the 75)
The calculation given is 100-25*3%4 with an answer of 97. Now this is how I would get it using PEMDAS as he speaks of in the question section:
#!/bin/python
A = 100
B = 25
C = 3
D = 4
E = B*C # 75
F = E%D # 3
G = A-F # 97
print("B * C ="), E
print("E % D ="), F
print("A - F ="), G
I think you have to treat modulo (%) as a division,
Python evaluates % after * but before + or _ .
So,
(100 - 25 * 3 % 4)
(100 - 75 % 4)
(100 - 3)
(97)

Categories