What is the time complexity of this recursion? - python

def s_r(n):
if(n==1):
return 1
temp = 1
for i in range(int(n)):
temp += i
return temp * s_r(n/2) * s_r(n/2) * s_r(n/2) * s_r(n/2)
Using recursion tree what’s the Big Oh
And also how do we write this function into one recursive call.
I could only do the first part which I got O(n^2). This was one my exam questions which I want to know the answer and guidance to. Thank you

First, note that the program is incorrect: n/2 is floating point division in python (since Python3), so the program does not terminate unless n is a power of 2 (or eventually rounds to a power of 2). The corrected version of the program that works for all integer n>=1, is this:
def s_r(n):
if(n==1):
return 1
temp = 1
for i in range(n):
temp += i
return temp * s_r(n//2) * s_r(n//2) * s_r(n//2) * s_r(n//2)
If T(n) is the number of arithmetic operations performed by the function, then we have the recurrence relation:
T(1) = 0
T(n) = n + 4T(n//2)
T(n) is Theta(n^2) -- for n a power of 2 and telescoping we get: n + 4(n/2) + 16(n/4) + ... = 1n + 2n + 4n + 8n + ... + nn = (2n-1)n
We can rewrite the program to use Theta(log n) arithmetic operations. First, the temp variable is 1 + 0+1+...+(n-1) = n(n-1)/2 + 1. Second, we can avoid making the same recursive call 4 times.
def s_r(n):
return (1 + n * (n-1) // 2) * s_r(n//2) ** 4 if n > 1 else 1
Back to complexity, I have been careful to say that the first function does Theta(n^2) arithmetic operations and the second Theta(log n) arithmetic operations, rather than use the expression "time complexity". The result of the function grows FAST, so it's not practical to assume arithmetic operations run in O(1) time. If we print the length of the result and the time taken to compute it (using the second, faster version of the code) for powers of 2 using this...
import math
import timeit
def s_r(n):
return (1 + n * (n-1) // 2) * s_r(n//2) ** 4 if n > 1 else 1
for i in range(16):
n = 2 ** i
start = timeit.default_timer()
r = s_r(n)
end = timeit.default_timer()
print('n=2**%d,' % i, 'digits=%d,' % (int(math.log(r))+1), 'time=%.3gsec' % (end - start))
... we get this table, in which you can see the number of digits in the result grows FAST (s_r(2**14) has 101 million digits for example), and the time measured does not grow with log(n), but when n is doubled the time increases by something like a factor of 10, so it grows something like n^3 or n^4.
n=2**0, digits=1, time=6e-07sec
n=2**1, digits=1, time=1.5e-06sec
n=2**2, digits=5, time=9e-07sec
n=2**3, digits=23, time=1.1e-06sec
n=2**4, digits=94, time=2.1e-06sec
n=2**5, digits=382, time=2.6e-06sec
n=2**6, digits=1533, time=3.8e-06sec
n=2**7, digits=6140, time=3.99e-05sec
n=2**8, digits=24569, time=0.000105sec
n=2**9, digits=98286, time=0.000835sec
n=2**10, digits=393154, time=0.00668sec
n=2**11, digits=1572628, time=0.0592sec
n=2**12, digits=6290527, time=0.516sec
n=2**13, digits=25162123, time=4.69sec
n=2**14, digits=100648510, time=42.1sec
n=2**15, digits=402594059, time=377sec
Note that it's not wrong to say the time complexity of the original function is O(n^2) and the improved version of the code O(log n), it's just that these describe a measure of the program (arithmetic operations) and are not at all useful as an estimate of actual program running time.

As #kcsquared said in comments I also believe this function is O(n²). This code can be refactored into one function call by storing the result of recursion call, or just doing some math application. Also you can simplify the range sum, by using the built-in sum
def s_r(n):
if n == 1:
return 1
return (sum(range(int(n))) + 1) * s_r(n/2) ** 4

Related

Runtime of two nested for loops

I am calculating the run time complexity of the below Python code as n^2 but it seems that it is incorrect. The correct answer shown is n(n-1)/2. Can anyone help help me in understanding why the inner loop is not running n*n times but rather n(n-1)/2?
for i in range(n):
for j in range(i):
val += 1
On the first run of the inner loop, when i = 0, the for loop does not execute at all. (There are zero elements to iterate over in range(0)).
On the second run of the inner loop, when i = 1, the for loop executes for one iteration. (There is one element to iterate over in range(1)).
Then, there are two elements in the third run, three in the fourth, following this pattern, up until i = n - 1.
The total number of iterations is 0 + 1 + ... + (n - 1). This summation has a well known form*: for any natural m, 0 + 1 + ... + m = m * (m + 1) / 2. In this case, we have m = n - 1, so there are n * (n - 1) / 2 iterations in total.
You're right that the asymptotic time complexity of this algorithm is O(n^2). However, given that you've said that the "correct answer" is n * (n - 1) / 2, the question most likely asked for the exact number of iterations (rather than an asymptotic bound).
* See here for a proof of this closed form.

Is ther any other way to get sum 1 to 100 with recursion?

I'm studing recursive function and i faced question of
"Print sum of 1 to n with no 'for' or 'while' "
ex ) n = 10
answer =
55
n = 100
answer = 5050
so i coded
import sys
sys.setrecursionlimit(1000000)
sum = 0
def count(n):
global sum
sum += n
if n!=0:
count(n-1)
count(n = int(input()))
print(sum)
I know it's not good way to get right answer, but there was a solution
n=int(input())
def f(x) :
if x==1 :
return 1
else :
return ((x+1)//2)*((x+1)//2)+f(x//2)*2
print(f(n))
and it works super well , but i really don't know how can human think that logic and i have no idea how it works.
Can you guys explain how does it works?
Even if i'm looking that formula but i don't know why he(or she) used like that
And i wonder there is another solution too (I think it's reall important to me)
I'm really noob of python and code so i need you guys help, thank you for watching this
Here is a recursive solution.
def rsum(n):
if n == 1: # BASE CASE
return 1
else: # RECURSIVE CASE
return n + rsum(n-1)
You can also use range and sum to do so.
n = 100
sum_1_to_n = sum(range(n+1))
you can try this:
def f(n):
if n == 1:
return 1
return n + f(n - 1)
print(f(10))
this function basically goes from n to 1 and each time it adds the current n, in the end, it returns the sum of n + n - 1 + ... + 1
In order to get at a recursive solution, you have to (re)define your problems in terms of finding the answer based on the result of a smaller version of the same problem.
In this case you can think of the result sumUpTo(n) as adding n to the result of sumUpTo(n-1). In other words: sumUpTo(n) = n + sumUpTo(n-1).
This only leaves the problem of finding a value of n for which you know the answer without relying on your sumUpTo function. For example sumUpTo(0) = 0. That is called your base condition.
Translating this to Python code, you get:
def sumUpTo(n): return 0 if n==0 else n + sumUpTo(n-1)
Recursive solutions are often very elegant but require a different way of approaching problems. All recursive solutions can be converted to non-recursive (aka iterative) and are generally slower than their iterative counterpart.
The second solution is based on the formula ∑1..n = n*(n+1)/2. To understand this formula, take a number (let's say 7) and pair up the sequence up to that number in increasing order with the same sequence in decreasing order, then add up each pair:
1 2 3 4 5 6 7 = 28
7 6 5 4 3 2 1  = 28
-- -- -- -- -- -- -- --
8 8 8 8 8 8 8 = 56
Every pair will add up to n+1 (8 in this case) and you have n (7) of those pairs. If you add them all up you get n*(n+1) = 56 which correspond to adding the sequence twice. So the sum of the sequence is half of that total n*(n+1)/2 = 28.
The recursion in the second solution reduces the number of iterations but is a bit artificial as it serves only to compensate for the error introduced by propagating the integer division by 2 to each term instead of doing it on the result of n*(n+1). Obviously n//2 * (n+1)//2 isn't the same as n*(n+1)//2 since one of the terms will lose its remainder before the multiplication takes place. But given that the formula to obtain the result mathematically is part of the solution doing more than 1 iteration is pointless.
There are 2 ways to find the answer
1. Recursion
def sum(n):
if n == 1:
return 1
if n <= 0:
return 0
else:
return n + sum(n-1)
print(sum(100))
This is a simple recursion code snippet when you try to apply the recurrent function
F_n = n + F_(n-1) to find the answer
2. Formula
Let S = 1 + 2 + 3 + ... + n
Then let's do something like this
S = 1 + 2 + 3 + ... + n
S = n + (n - 1) + (n - 2) + ... + 1
Let's combine them and we get
2S = (n + 1) + (n + 1) + ... + (n + 1) - n times
From that you get
S = ((n + 1) * n) / 2
So for n = 100, you get
S = 101 * 100 / 2 = 5050
So in python, you will get something like
sum = lambda n: ( (n + 1) * n) / 2
print(sum(100))

Is my Sieve of Eratosthenes implemented correctly? (Python) [duplicate]

This question already has answers here:
Sieve of Eratosthenes - Finding Primes Python
(22 answers)
Closed 4 years ago.
I need to generate a large number of prime numbers, however it is taking far too long using the Sieve of Eratosthenes. Currently it takes roughly 3 seconds to generate primes under 100,000 and roughly 30 for primes under 1,000,000. Which seems to indicate an O(n) complexity but as far as I know that's not right. Code:
def generate_primes(limit):
boolean_list = [False] * 2 + [True] * (limit - 1)
for n in range(2, int(limit ** 0.5 + 1)):
if boolean_list[n] == True:
for i in range(n ** 2, limit + 1, n):
boolean_list[i] = False
Am I missing something obvious? How can I improve the performance of the sieve?
Loop indexing is well known in Python to be an incredibly slow operation. By replacing a loop with array slicing, and a list with a Numpy array, we see increases # 3x:
import numpy as np
import timeit
def generate_primes_original(limit):
boolean_list = [False] * 2 + [True] * (limit - 1)
for n in range(2, int(limit ** 0.5 + 1)):
if boolean_list[n] == True:
for i in range(n ** 2, limit + 1, n):
boolean_list[i] = False
return np.array(boolean_list,dtype=np.bool)
def generate_primes_fast(limit):
boolean_list = np.array([False] * 2 + [True] * (limit - 1),dtype=bool)
for n in range(2, int(limit ** 0.5 + 1)):
if boolean_list[n]:
boolean_list[n*n:limit+1:n] = False
return boolean_list
limit = 1000
print(timeit.timeit("generate_primes_fast(%d)"%limit, setup="from __main__ import generate_primes_fast"))
# 30.90620080102235 seconds
print(timeit.timeit("generate_primes_original(%d)"%limit, setup="from __main__ import generate_primes_original"))
# 91.12803511600941 seconds
assert np.array_equal(generate_primes_fast(limit),generate_primes_original(limit))
# [nothing to stdout - they are equal]
To gain even more speed, one option is to use numpy vectorization. Looking at the outer loop, it's not immediately obvious how one could vectorize that.
Second, you will see dramatic speed-ups if you port to Cython, which should be a fairly seamless process.
Edit: you may also see improvements by changing things like n**2 => math.pow(n,2), but minor improvements like that are inconsequential compared to the bigger problem, which is the iterator.
If your are still using Python 2 use xrange instead of range for greater speed

What is the runtime for this code

def mystery11(n):
if n < 1: return n
def mystery12(n):
i = 1
while i < n:
i *= 2
return i
return mystery11(n/2) + mystery11(n/2) + mystery12(n-2)
I have a question about the code above. I completely understand that without the last recursive call to mystery12, the runtime of the code (mystery11) would be theta(n). But I don't believe that at each level theta(log(n)) work is being done.
At the first level, we do log(n), at the next level, we do 2log(n/2), then 4log(n/4)... but that doesn't look like log(n) at each level (it feels closer to 2log(n) at the second level and 4log(n) at the third level etc.)
I've also tried Wolfram Alpha, and I just get no solutions exist.
But works fine without the log(n) term.
So, is this solution correct theta(nlog(n))? And if not, what is the actual solution?
Ps. Apologies if anything in my post is not etiquette, this is my second time posting on Stackoverflow. Post a comment and I will fix it.
Since mystery12 is independent of any external functions / variables, let's look at it first.
After the j-th iteration of the while-loop, i = 2^j. Therefore the maximum number of loops is given by the equation 2^j >= n, or j = ceil(log2(n)) where ceil rounds up to the nearest integer.
Now for mystery11. Each call contains 2 recursive calls to mystery11 with argument n / 2, and a call to mystery12 with argument n - 2. This gives the time complexity recurrence relation (C is some positive constant):
You have already correctly deduced that the recursion depth is m ~ log n. The precise value is m = ceil(log2(n)). Using the fact that a number rounded up only differs from itself by less than 1, we can eliminate some of the rounding brackets:
Let's examine B first. A problem arises - the expression inside the logarithm can be negative. This is mitigated by the fact that the while-loop mystery12 never executes if n - 2 < 1 - i.e. its complexity can be truncated to O(1) in this edge case. Therefore, the sum is bounded from above by:
Where we used a Taylor expansion of log. Hence B can be ignored in our analysis as it is already overshadowed by the first term.
Now to examine A. This is a slightly tedious summation which I will use Wolfram Alpha to compute:
Therefore the overal time complexity of mystery11 is Θ(n), not Θ(n log n) as predicted.
Why is this? The reason lies in "each recursive call does log n work" - n here is not the same as the initial value of n passed to mystery11 (the n in the overall time complexity). At each recursion level n decreases exponentially, so:
We cannot naively multiply the amount of work done per call with the number of recursive calls.
This applies to complexity analysis in general.
I'm sorry I couldn't understand what your question is.
It seems not clear to me.
Whatever it is,
I did the math according to your 'mystery' code.
Let's say 'm1' is the mystery11, 'm2' is the mystery12.
Without m2,
time cost would be like this.
m1(n)
= 2*m1(n/2)
= 2*( m1(n/4) + m1(n/4) ) = 4*m1(n/4)
= .....
= 2^k * m1( n / 2^k )
For the k which makes 2^k n,
2^k = n.
Then time cost for m1(n) is n * m1(1) = n.
Time cost of m2 is log(n) obviously.
With m2,
time cost changes like this.
m1(n)
= 2*m1(n/2) + log(n)
= 2*( m1(n/4) + m1(n/4) + log(n) ) + log(n) = 4*m1(n/4) + ( log(n) + 2log(n) )
= ....
= 2^k * m1(n/2^k) + ( log(n) + 2log(n) + 4log(n) ... 2^(k-1)*log(n) )
= 2^k * m1(n/2^k) + log(n) * ∑( 2^(k-1) ) ( where k is from 1 to k )
= 2^k * m1(n/2^k) + log(n)/2 * ∑( 2^k )
= 2^k * m1(n/2^k) + log(n)/2 * ( 2^(k+1) - 1 )
= 2^k * m1(n/2^k) + 2^k * log(n) - log(n)/2
Just like the previous one,
for the k which makes 2^k n,
2^k * m1(n/2^k) + 2^k * log(n) - log(n)/2
= n * m1(1) + n*log(n) - log(n)/2 = n + n*log(n) - log(n)/2
I believe you can do the rest from here.
Ps. My apologies if it's not what you asked for.

Generating digits of square root of 2

I want to generate the digits of the square root of two to 3 million digits.
I am aware of Newton-Raphson but I don't have much clue how to implement it in C or C++ due to lack of biginteger support. Can somebody point me in the right direction?
Also, if anybody knows how to do it in python (I'm a beginner), I would also appreciate it.
You could try using the mapping:
a/b -> (a+2b)/(a+b) starting with a= 1, b= 1. This converges to sqrt(2) (in fact gives the continued fraction representations of it).
Now the key point: This can be represented as a matrix multiplication (similar to fibonacci)
If a_n and b_n are the nth numbers in the steps then
[1 2] [a_n b_n]T = [a_(n+1) b_(n+1)]T
[1 1]
which now gives us
[1 2]n [a_1 b_1]T = [a_(n+1) b_(n+1)]T
[1 1]
Thus if the 2x2 matrix is A, we need to compute An which can be done by repeated squaring and only uses integer arithmetic (so you don't have to worry about precision issues).
Also note that the a/b you get will always be in reduced form (as gcd(a,b) = gcd(a+2b, a+b)), so if you are thinking of using a fraction class to represent the intermediate results, don't!
Since the nth denominators is like (1+sqrt(2))^n, to get 3 million digits you would likely need to compute till the 3671656th term.
Note, even though you are looking for the ~3.6 millionth term, repeated squaring will allow you to compute the nth term in O(Log n) multiplications and additions.
Also, this can easily be made parallel, unlike the iterative ones like Newton-Raphson etc.
EDIT: I like this version better than the previous. It's a general solution that accepts both integers and decimal fractions; with n = 2 and precision = 100000, it takes about two minutes. Thanks to Paul McGuire for his suggestions & other suggestions welcome!
def sqrt_list(n, precision):
ndigits = [] # break n into list of digits
n_int = int(n)
n_fraction = n - n_int
while n_int: # generate list of digits of integral part
ndigits.append(n_int % 10)
n_int /= 10
if len(ndigits) % 2: ndigits.append(0) # ndigits will be processed in groups of 2
decimal_point_index = len(ndigits) / 2 # remember decimal point position
while n_fraction: # insert digits from fractional part
n_fraction *= 10
ndigits.insert(0, int(n_fraction))
n_fraction -= int(n_fraction)
if len(ndigits) % 2: ndigits.insert(0, 0) # ndigits will be processed in groups of 2
rootlist = []
root = carry = 0 # the algorithm
while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
carry = carry * 100
if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
x = 9
while (20 * root + x) * x > carry:
x -= 1
carry -= (20 * root + x) * x
root = root * 10 + x
rootlist.append(x)
return rootlist, decimal_point_index
As for arbitrary big numbers you could have a look at The GNU Multiple Precision Arithmetic Library (for C/C++).
For work? Use a library!
For fun? Good for you :)
Write a program to imitate what you would do with pencil and paper. Start with 1 digit, then 2 digits, then 3, ..., ...
Don't worry about Newton or anybody else. Just do it your way.
Here is a short version for calculating the square root of an integer a to digits of precision. It works by finding the integer square root of a after multiplying by 10 raised to the 2 x digits.
def sqroot(a, digits):
a = a * (10**(2*digits))
x_prev = 0
x_next = 1 * (10**digits)
while x_prev != x_next:
x_prev = x_next
x_next = (x_prev + (a // x_prev)) >> 1
return x_next
Just a few caveats.
You'll need to convert the result to a string and add the decimal point at the correct location (if you want the decimal point printed).
Converting a very large integer to a string isn't very fast.
Dividing very large integers isn't very fast (in Python) either.
Depending on the performance of your system, it may take an hour or longer to calculate the square root of 2 to 3 million decimal places.
I haven't proven the loop will always terminate. It may oscillate between two values differing in the last digit. Or it may not.
The nicest way is probably using the continued fraction expansion [1; 2, 2, ...] the square root of two.
def root_two_cf_expansion():
yield 1
while True:
yield 2
def z(a,b,c,d, contfrac):
for x in contfrac:
while a > 0 and b > 0 and c > 0 and d > 0:
t = a // c
t2 = b // d
if not t == t2:
break
yield t
a = (10 * (a - c*t))
b = (10 * (b - d*t))
# continue with same fraction, don't pull new x
a, b = x*a+b, a
c, d = x*c+d, c
for digit in rdigits(a, c):
yield digit
def rdigits(p, q):
while p > 0:
if p > q:
d = p // q
p = p - q * d
else:
d = (10 * p) // q
p = 10 * p - q * d
yield d
def decimal(contfrac):
return z(1,0,0,1,contfrac)
decimal((root_two_cf_expansion()) returns an iterator of all the decimal digits. t1 and t2 in the algorithm are minimum and maximum values of the next digit. When they are equal, we output that digit.
Note that this does not handle certain exceptional cases such as negative numbers in the continued fraction.
(This code is an adaptation of Haskell code for handling continued fractions that has been floating around.)
Well, the following is the code that I wrote. It generated a million digits after the decimal for the square root of 2 in about 60800 seconds for me, but my laptop was sleeping when it was running the program, it should be faster that. You can try to generate 3 million digits, but it might take a couple days to get it.
def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
if number[a]=='.':
decimal_point_locaiton=a
break
if a==len(number)-1:
number+='.'
decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
number='0'+number
decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
if number[a]!='0':
list.append(eval(number[a:a+2]))
else:
try:
list.append(eval(number[a+1]))
except IndexError:
pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
try:
c=c*100+list[a+1]
except IndexError:
c=c*100
while c!=0:
x=0
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
c=c*100
if len(ans)-decimal_point_ans>=digits_after_decimal:
break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total
Python already supports big integers out of the box, and if that's the only thing holding you back in C/C++ you can always write a quick container class yourself.
The only problem you've mentioned is a lack of big integers. If you don't want to use a library for that, then are you looking for help writing such a class?
Here's a more efficient integer square root function (in Python 3.x) that should terminate in all cases. It starts with a number much closer to the square root, so it takes fewer steps. Note that int.bit_length requires Python 3.1+. Error checking left out for brevity.
def isqrt(n):
x = (n >> n.bit_length() // 2) + 1
result = (x + n // x) // 2
while abs(result - x) > 1:
x = result
result = (x + n // x) // 2
while result * result > n:
result -= 1
return result

Categories