recursively calculate if x is power of b - python

The assignment is to write a recursive function that receives 2 whole non-negative numbers b, x, and returns True if there's a natural integer n so that b**n=x and False if not. I'm not allowed to use any math operators or loops, except % to determine if a number is even or odd.
but i do have external functions that i can use. Which can add 2 numbers, multiply 2 numbers, and divides a number by 2. also i can write helper function that i can use in the main function.
this is what i got so far, but it only works if b is in the form of 2^y (2,4,8,16 etc)
def is_power(b, x):
if b == x:
return True
if b > x:
return False
return is_power(add(b, b), x) # the func 'add' just adds 2 numbers
Furthermore, the complexity needs to be O(logb * logx)
Thank you.

You can essentially keep multiplying b by b until you reach, or pass, n.
A recursive implementation of this, using a helper function, could look something like this:
def is_power(b, x):
if b == 1: # Check special case
return x == 1
return helper(1, b, x)
def helper(counter, b, x):
if counter == x:
return True
elif counter > x:
return False
else:
return helper(mul(counter, b), b, x) # mul is our special multiplication function

Use the function you say you can use to multiply 2 numbers like:
power = False
result = b
while result < x:
result = yourMultiplyFunction(b,b)
if result == x:
power = True
break
print(power)
Question was EDITTED (can't use loops):
def powerOf(x, b, b1=-1):
if b1 == -1:
b1 = b
if (b == 1) and (x == 1):
return True
elif ( b==1 ) or (x == 1):
return False
if b*b1 < x:
return powerOf(x, b*b1, b1)
elif b*b1 > x:
return False
return True
print(powerOf(625, 25))

A solution that is O(logb * logx) would be slower than a naive sequential search
You can get O(logx / logb) by simply doing this:
def is_power(b,x,bn=1):
if bn == x: return True
if bn > x: return False
return is_power(b,x,bn*b)
I suspect that the objective is to go faster than O(logx/logb) and that the complexity requirement should be something like O(log(logx/logb)^2) which is equivalent to O(log(n)*log(n)).
To get a O(log(n)*log(n)) solution, you can convert the problem into a binary search by implementing a helper function to raise a number to a given power in O(log(n)) time and use it in the O(log(n)) search logic.
def raise_power(b,n): # recursive b^n O(logN)
if not n: return 1 # b^0 = 1
if n%2: return b*raise_power(b*b,n//2) # binary decomposition
return raise_power(b*b,n//2) # of power over base
def find_power(b,x,minp,maxp): # binary search
if minp>maxp: return False # no matching power
n = (minp+maxp)//2 # middle of exponent range
bp = raise_power(b,n) # compute power
if bp == x: return True # match found
if bp > x: return find_power(b,x,minp,n-1) # look in lower sub-range
return find_power(b,x,n+1,maxp) # look in upper sub-range
def max_power(b,x):
return 2*max_power(b*b,x) if b<x else 1 # double n until b^n > x
def is_power(b,x):
maxp = max_power(b,x) # determine upper bound
return find_power(b,x,0,maxp) # use binary search
Note that you will need to convert the *, + and //2 operations to their equivalent external functions in order to meet the requirements of your assignment

Related

Least Common Multiple of 2 numbers by prime factors of number

In this code, I am trying to get prime factors for the prime method to find LCM. then I am trying to save it by counter but I am not able to divide both key and values for the proper method.
I'm stuck at counter, please can anyone help me?
from collections import Counter
def q2_factor_lcm(a, b): #function for lcm
fa = factor_list(a) #factor list for a
fb = factor_list(b) #factorlist for b
c = Counter(fa) #variables to save counter for a
d = Counter(fb) #variables to save counter for b
r = c | d
r.keys()
for key, value in sorted(r.items()): # for loop for getting counter subtraction
l = pow(key, value)
result = [] # I am getting confused what to do now
for item in l:
result.append(l)
return result #will return result
def factor_list(n): # it is to generate prime numbers
factors = [] # to save list
iprimes = iter( primes_list(n) ) # loop
while n > 1:
p = next(iprimes)
while n % p == 0: # python calculation
n = n // p
factors.append(p)
return factors # it will return factors
First this method is not really efficient to find a lcm. As there are some nice and clean algo to find a gcd, it is easier to get the lcm of a and b by lcm = a * b / gcd(a,b) (*).
Second, never use pow with integer values. Floating point arithmetics is know to be broken not accurate.
Now for your question. The update operation on the 2 counters in not what you want: you lose one of the values when a key is present in both dicts. You should instead use the union of the key sets, and then use the max of both values (a non existent key is seen as a 0 value for the exponent):
...
# use a true dict to be able to later use the get method with a default
c = dict(Counter(fa)) #variables to save counter for a
d = dict(Counter(fb)) #variables to save counter for b
result = []
for key in sorted(set(c.keys()).union(set(d.keys()))):
exp = max(c.get(key, 0), d.get(key, 0))
for i in range(exp):
result.append(key)
return result
(*) The trick is that when a > b, GCD(a,b) is GCD(b, mod(a,b)). In Python it gives immediately:
def gcd(a, b):
if b > a:
return gcd(b, a)
if b == 1:
return b
m = a % b
return b if m == 0 else gcd(b, m)
def lcm(a,b):
return a * b / gcd(a,b)

Decimal To Binary Python Getting an Extra Zero In Return String

This is for a school project. I need to create a function using recursion to convert an integer to binary string. It must be a str returned, not an int. The base case is n==0, and then 0 would need to be returned. There must be a base case like this, but this is where I think I am getting the extra 0 from (I could be wrong). I am using Python 3.6 with the IDLE and the shell to execute it.
The function works just fine, expect for this additional zero that I need gone.
Here is my function, dtobr:
def dtobr(n):
"""
(int) -> (str)
This function has the parameter n, which is a non-negative integer,
and it will return the string of 0/1's
which is the binary representation of n. No side effects.
Returns bianry string as mentioned. This is like the function
dtob (decimal to bianary) but this is using recursion.
Examples:
>>> dtob(27)
'11011'
>>> dtob(0)
'0'
>>> dtob(1)
'1'
>>> dtob(2)
'10'
"""
if n == 0:
return str(0)
return dtobr(n // 2) + str(n % 2)
This came from the function I already wrote which converted it just fine, but without recursion. For reference, I will include this code as well, but this is not what I need for this project, and there are no errors with this:
def dtob(n):
"""
(int) -> (str)
This function has the parameter n, which is a non-negative integer,
and it will return the string of 0/1's
which is the binary representation of n. No side effects.
Returns bianry string as mentioned.
Examples:
>>> dtob(27)
'11011'
>>> dtob(0)
'0'
>>> dtob(1)
'1'
>>> dtob(2)
'10'
"""
string = ""
if n == 0:
return str(0)
while n > 0:
remainder = n % 2
string = str(remainder) + string
n = n // 2
Hopefully someone can help me get ride of that additional left hand zero. Thanks!
You need to change the condition to recursively handle both the n // 2 and n % 2:
if n <= 1:
return str(n) # per #pault's suggestion, only needed str(n) instead of str(n % 2)
else:
return dtobr(n // 2) + dtobr(n % 2)
Test case:
for i in [0, 1, 2, 27]:
print(dtobr(i))
# 0
# 1
# 10
# 11011
FYI you can easily convert to binary format like so:
'{0:b}'.format(x) # where x is your number
Since there is already an answer that points and resolves the issue with recursive way, lets see some interesting ways to achieve same goal.
Lets define a generator that will give us iterative way of getting binary numbers.
def to_binary(n):
if n == 0: yield "0"
while n > 0:
yield str(n % 2)
n = n / 2
Then you can use this iterable to get decimal to binary conversion in multiple ways.
Example 1.
reduce function is used to concatenate chars received from to_binary iterable (generator).
from functools import reduce
def to_binary(n):
if n == 0: yield "0"
while n > 0:
yield str(n % 2)
n = n / 2
print reduce(lambda x, y: x+y, to_binary(0)) # 0
print reduce(lambda x, y: x+y, to_binary(15)) # 1111
print reduce(lambda x, y: x+y, to_binary(15)) # 11011
Example 2.
join takes iterable, unrolls it and joins them by ''
def to_binary(n):
if n == 0: yield "0"
while n > 0:
yield str(n % 2)
n = n / 2
print ''.join(to_binary(0)) # 0
print ''.join(to_binary(1)) # 1
print ''.join(to_binary(15)) # 1111
print ''.join(to_binary(27)) # 11011

Recursive to iterative using a systematic method [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 3 years ago.
Improve this question
I've started reading the book Systematic Program Design: From Clarity to Efficiency few days ago. Chapter 4 talks about a systematic method to convert any recursive algorithm into its counterpart iterative. It seems this is a really powerful general method but I'm struggling quite a lot to understand how it works.
After reading a few articles talking about recursion removal using custom stacks, it feels like this proposed method would produce a much more readable, optimized and compact output.
Recursive algorithms in Python where I want to apply the method
#NS: lcs and knap are using implicit variables (i.e.: defined globally), so they won't
#work directly
# n>=0
def fac(n):
if n==0:
return 1
else:
return n*fac(n-1)
# n>=0
def fib(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib(n-1)+fib(n-2)
# k>=0, k<=n
def bin(n,k):
if k==0 or k==n:
return 1
else:
return bin(n-1,k-1)+bin(n-1,k)
# i>=0, j>=0
def lcs(i,j):
if i==0 or j==0:
return 0
elif x[i]==y[j]:
return lcs(i-1,j-1)+1
else:
return max(lcs(i,j-1),lcs(i-1,j))
# i>=0, u>=0, for all i in 0..n-1 w[i]>0
def knap(i,u):
if i==0 or u==0:
return 0
elif w[i]>u:
return knap(i-1,u)
else:
return max(v[i]+knap(i-1,u-w[i]), knap(i-1,u))
# i>=0, n>=0
def ack(i,n):
if i==0:
return n+1
elif n==0:
return ack(i-1,1)
else:
return ack(i-1,ack(i,n-1))
Step Iterate: Determine minimum increments, transform recursion into iteration
The Section 4.2.1 the book talks about determining the appropriate increment:
1) All possible recursive calls
fact(n) => {n-1}
fib(n) => {fib(n-1), fib(n-2)}
bin(n,k) => {bin(n-1,k-1),bin(n-1,k)}
lcs(i,j) => {lcs(i-1,j-1),lcs(i,j-1),lcs(i-1,j)}
knap(i,u) => {knap(i-1,u),knap(i-1,u-w[i])}
ack(i,n) => {ack(i-1,1),ack(i-1,ack(i,n-1)), ack(i,n-1)}
2) Decrement operation
fact(n) => n-1
fib(n) => n-1
bin(n,k) => [n-1,k]
lcs(i,j) => [i-1,j]
knap(i,u) => [i-1,u]
ack(i,n) => [i,n-1]
3) Minimum increment operation
fact(n) => next(n) = n+1
fib(n) => next(n) = n+1
bin(n,k) => next(n,k) = [n+1,k]
lcs(i,j) => next(i,j) = [i+1,j]
knap(i,u) => next(i,u) = [i+1,u]
ack(i,n) => next(i,n) = [i,n+1]
Section 4.2.2 talks about forming the optimized program:
Recursive
---------
def fExtOpt(x):
if base_cond(x) then fExt0(x ) -- Base case
else let rExt := fExtOpt(prev(x)) in -- Recursion
f Ext’(prev(x),rExt) -- Incremental computation
Iterative
---------
def fExtOpt(x):
if base_cond(x): return fExt0(x) -- Base case
x1 := init_arg; rExt := fExt0(x1) -- Initialization
while x1 != x: -- Iteration
x1 := next(x1); rExt := fExt’(prev(x1),rExt) -- Incremental comp
return rExt
How do I create {fibExtOpt,binExtOpt,lcsExtOpt,knapExtOpt,ackExtOpt} in Python?
Additional material about this topic can be found in one of the papers of the main author of the method, Y. Annie Liu, Professor.
So, to restate the question. We have a function f, in our case fac.
def fac(n):
if n==0:
return 1
else:
return n*fac(n-1)
It is implemented recursively. We want to implement a function facOpt that does the same thing but iteratively. fac is written almost in the form we need. Let us rewrite it just a bit:
def fac_(n, r):
return (n+1)*r
def fac(n):
if n==0:
return 1
else:
r = fac(n-1)
return fac_(n-1, r)
This is exactly the recursive definition from section 4.2. Now we need to rewrite it iteratively:
def facOpt(n):
if n==0:
return 1
x = 1
r = 1
while x != n:
x = x + 1
r = fac_(x-1, r)
return r
This is exactly the iterative definition from section 4.2. Note that facOpt does not call itself anywhere. Now, this is neither the most clear nor the most pythonic way of writing down this algorithm -- this is just a way to transform one algorithm to another. We can implement the same algorithm differently, e.g. like that:
def facOpt(n):
r = 1
for x in range(1, n+1):
r *= x
return r
Things get more interesting when we consider more complicated functions. Let us write fibObt where fib is :
def fib(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib(n-1) + fib(n-2)
fib calls itself two times, but the recursive pattern from the book allows only a single call. That is why we need to extend the function to returning not one, but two values. Fully reformated, fib looks like this:
def fibExt_(n, rExt):
return rExt[0] + rExt[1], rExt[0]
def fibExt(n):
if n == 0:
return 0, 0
elif n == 1:
return 1, 0
else:
rExt = fibExt(n-1)
return fibExt_(n-1, rExt)
def fib(n):
return fibExt(n)[0]
You may notice that the first argument to fibExt_ is never used. I just added it to follow the proposed structure exactly.
Now, it is again easy to turn fib into an iterative version:
def fibExtOpt(n):
if n == 0:
return 0, 0
if n == 1:
return 1, 0
x = 2
rExt = 1, 1
while x != n:
x = x + 1
rExt = fibExt_(x-1, rExt)
return rExt
def fibOpt(n):
return fibExtOpt(n)[0]
Again, the new version does not call itself. And again one can streamline it to this, for example:
def fibOpt(n):
if n < 2:
return n
a, b = 1, 1
for i in range(n-2):
a, b = b, a+b
return b
The next function to translate to iterative version is bin:
def bin(n,k):
if k == 0 or k == n:
return 1
else:
return bin(n-1,k-1) + bin(n-1,k)
Now neither x nor r can be just numbers. The index (x) has two components, and the cache (r) has to be even larger. One (not quite so optimal) way would be to return the whole previous row of the Pascal triangle:
def binExt_(r):
return [a + b for a,b in zip([0] + r, r + [0])]
def binExt(n):
if n == 0:
return [1]
else:
r = binExt(n-1)
return binExt_(r)
def bin(n, k):
return binExt(n)[k]
I have't followed the pattern so strictly here and removed several useless variables. It is still possible to translate to an iterative version directly:
def binExtOpt(n):
if n == 0:
return [1]
x = 1
r = [1, 1]
while x != n:
r = binExt_(r)
x += 1
return r
def binOpt(n, k):
return binExtOpt(n)[k]
For completeness, here is an optimized solution that caches only part of the row:
def binExt_(n, k_from, k_to, r):
if k_from == 0 and k_to == n:
return [a + b for a, b in zip([0] + r, r + [0])]
elif k_from == 0:
return [a + b for a, b in zip([0] + r[:-1], r)]
elif k_to == n:
return [a + b for a, b in zip(r, r[1:] + [0])]
else:
return [a + b for a, b in zip(r[:-1], r[1:])]
def binExt(n, k_from, k_to):
if n == 0:
return [1]
else:
r = binExt(n-1, max(0, k_from-1), min(n-1, k_to+1) )
return binExt_(n, k_from, k_to, r)
def bin(n, k):
return binExt(n, k, k)[0]
def binExtOpt(n, k_from, k_to):
if n == 0:
return [1]
ks = [(k_from, k_to)]
for i in range(1,n):
ks.append((max(0, ks[-1][0]-1), min(n-i, ks[-1][1]+1)))
x = 0
r = [1]
while x != n:
x += 1
r = binExt_(x, *ks[n-x], r)
return r
def binOpt(n, k):
return binExtOpt(n, k, k)[0]
In the end, the most difficult task is not switching from recursive to iterative implementation, but to have a recursive implementation that follows the required pattern. So the real question is how to create fibExt', not fibExtOpt.

sum variable in a range (python)

This was the question:
Write a function called sum_range that accepts 2 integer values as
parameters and returns the sum of all the integers between the two
values, including the first and last values. The parameters may be in
any order (i.e. the second parameter may be smaller than the first).
For example:
result = sum_range(1, 1)
print(result) 1
result = sum_range(2, 4) print(result) 9
result = sum_range(3, 2)
print(result) 5
my codes are as below, I dont know where it went wrong
but when I test the codes, it returned 'none' when (2,4) (3,2) were entered
def sum_range(x,y):
if x == y:
return x
if x<y:
sum(range(x,y))
return
if x>y:
sum(range(y,x))
return
You could do better (at least I think), here is my code for that:
def sum_range(a, b):
return sum(range(min(a,b),max(a,b)+1))
You were very close but forgot to return the actual value from the calculations. If you just type "return", you will return None and not the result from the sum.
You also did not include the last number in the range in the sum. See corrected code below:
def sum_range(x, y):
if x == y:
return x
if x < y:
return sum(range(x, y+1))
if x > y:
return sum(range(y, x+1))
You need to return the sum which you are not doing in the x<y and x>y cases. You should
return sum(range(x,y)) or return sum(range(y,x)) as appropriate.
Note also that there is a bug in your range() expressions - "including the first and last values". Hint: What does range(1,3) output?
def sum_range(x,y):
if x == y:
return x
elif x < y:
s = 0
for i in range(x,y):
s += x+(x+1)
return s
elif x > y:
s = 0
for i in range(y,x):
s += y+(y+1)
return s
This is done without using sum() function.

Repeat function python

I'm stuck at higher-order functions in python. I need to write a repeat function repeat that applies the function f n times on a given argument x.
For example, repeat(f, 3, x) is f(f(f(x))).
This is what I have:
def repeat(f,n,x):
if n==0:
return f(x)
else:
return repeat(f,n-1,x)
When I try to assert the following line:
plus = lambda x,y: repeat(lambda z:z+1,x,y)
assert plus(2,2) == 4
It gives me an AssertionError. I read about How to repeat a function n times but I need to have it done in this way and I can't figure it out...
You have two problems:
You are recursing the wrong number of times (if n == 1, the function should be called once); and
You aren't calling f on the returned value from the recursive call, so the function is only ever applied once.
Try:
def repeat(f, n, x):
if n == 1: # note 1, not 0
return f(x)
else:
return f(repeat(f, n-1, x)) # call f with returned value
or, alternatively:
def repeat(f, n, x):
if n == 0:
return x # note x, not f(x)
else:
return f(repeat(f, n-1, x)) # call f with returned value
(thanks to #Kevin for the latter, which supports n == 0).
Example:
>>> repeat(lambda z: z + 1, 2, 2)
4
>>> assert repeat(lambda z: z * 2, 4, 3) == 3 * 2 * 2 * 2 * 2
>>>
You've got a very simple error there, in the else block you are just passing x along without doing anything to it. Also you are applying x when n == 0, don't do that.
def repeat(f,n,x):
"""
>>> repeat(lambda x: x+1, 2, 0)
2
"""
return repeat(f, n-1, f(x)) if n > 0 else x

Categories

Resources