I'm trying to find whether a number is a power of 2 using recursion. However, I couldn't seem to figure out the correct solution. Here's what I've tried so far:
def is_power(n):
n = n/2
if n == 2:
return True
elif n > 2:
is_power(n)
else:
return False
if is_power(32):
print 'yes'
else:
print 'no'
Since '32' is a power of 2, I expected my code to return 'yes' as the output. However, the code outputs 'no' instead. What seems to be wrong with my code?
Since I already have an accepted answer here, I'll use this one to explain a bit why your approach is bad:
It uses recursion in python. Python needs to open up a stack frame for every call, so for very large numbers, this will be a bad way of solving this. It will even fail for very large integers.
I don't even think recursion in a non-purely-functional language like python is the intuitive thing to do here. There's a million easier ways to do this; for example, a while loop:
n = int(n)
while n>1:
if n/2 != n/2.0: #compare integer division to float division
return False
n = n/2
return True
Checking against power of two can be done in clever ways by realizing what the storage structure for integers on computers is: it's binary. So you could just count the binary 1s in your int's binary representation:
return bin(n).count('1') == 1
would also work. Of course, that would mean that python internally converts the integer to a string, which wastes memory on large numbers. So you might as well
power_of_2 = 1
while power_of_2 <= n:
if power_of_2 == n:
return True
power_of_2 *= 2
return False
simply compares your number to all smaller-or-equal powers of two. (which of course would probably take longer and use more memory, since your python interpreter will have to interpret python instead of just converting your integer to a string in C, but this is about algorithmic principles, right?) That way, you don't need to reserve memory just to count occurencies of 1 in your binary representation.
Of course, there's a one-liner that solves your issues, and I take it from the things I've learned writing in C/C++:
bool(n and not (n&(n-1)))
To explain n and not (n&(n-1)): n is True iff n != 0, which is would otherwise falsely qualify as power of 2.
For not (n&(n-1)): n&(n-1) checks whether something is not a power of 2, so we have to invert that. & is the bitwise "and" operator. To understand n & (n-1), imagine n is a power of 2, let's say 8. So n-1 == 7, and thus
8|0b1000
7|0b0111
--------
&|0b0000
as you can see, for all powers of two, n&(n-1) is 0, which evaluates to False. For all non-powers of two, you'll don't invert all the bits when subtracting 1, so n&(n-1) != 0, which evaluates to True.
elif n > 2:
is_power(n)
is missing the return:
def is_power(n):
n = n/2
if n == 2:
return True
elif n > 2:
return is_power(n)
else:
return False
thus, the "first" level of is_power returns nothing (or None, depending on how you check), which leads to output of no.
#kaveman correctly pointed out is_power(2) yields the wrong result.
You can fix that by halving 2 in the elif clause:
def is_power(n):
if not n == int(n):
return False
n = int(n)
if n == 1:
return True
elif n > 2:
return is_power(n/2.0)
else:
return False
EDIT: #will pointed out that I was mixing up python2 with python3 division. Using /2.0 fixes that. Also, in comments to the question he pointed out that 1 is a power of 2. Checking against ==1 instead of ==2 fixes that issue. Also, I added an int cast, which is not necessary for the power of 2 check (since well, IEEE754 floats are base 2 after all, so powers of 2 are exactly representable), but for non-2 bases, this will make the code portable.
The answer provided above is wrong.
Yes it will work for powers of two, but it will also give many false positives - as you are using integer division - because you are using python 2.7.
It would work if you were using from __future__ import division, which changes the behaviour of / - but this changes its behaviour throughout the program, which may not be what you want.
for example:
print 33/2 # 16
print 32/2 # 16
however, with from __future__ import division the outputs change to the correct (or at least more intuitive) results - to get the original integer math behaviour you need to use // instead (as in python3).
So the correct answer will be more like this:
def is_power(n):
n = n/2.0
if n == 2:
return True
elif n > 2:
return is_power(n)
else:
return False
Note the n= n/2.0 at the beginning.
You need to test your code works on several test cases, not just ones for which you want particular results.
Alternatively though, i would go with something like this:
def is_power(n):
if n == 2:
return True
elif n%2 != 0:
return False
else:
return is_power(n/2.0)
While this does not directly answer your question, the fastest way to implement this would be
def is_power(n):
return ((n & (n - 1)) == 0) and n != 0
While this has been covered in a previous post by Marcus, a 'bit' more explanation may help some. The binary representation of every number and the (number-1) share at least a single 1 bit, except if the number is a power of two. Further, all negative numbers share the leading bit, so are excluded by this method.
The only exception is the number 0, which doesn't share bits with the previous number -1, and may not be viewed as a power of 2. Therefore this needs an explicit check.
The binary table for the numbers will make this clear.
> Dcml Binary 5bit
> -15 10001
> -14 10010
> -13 10011
> -12 10100
> -11 10101
> -10 10110
> -9 10111
> -8 11000
> -7 11001
> -6 11010
> -5 11011
> -4 11100
> -3 11101
> -2 11110
> -1 11111
> 0 00000
> 1 00001
> 2 00010
> 3 00011
> 4 00100
> 5 00101
> 6 00110
> 7 00111
> 8 01000
> 9 01001
> 10 01010
> 11 01011
> 12 01100
> 13 01101
> 14 01110
> 15 01111
> 16 10000
No negative numbers in this signed number notation would satisfy the condition as they all share the most significant bit as 1. number 0 would satisfy the condition as 0&(any_other_number) == 0. If you need to implement this for very large numbers you may be better off using bitarrays or numpy with changed dtype. Also, this discussion may be helpful for speed of bitwise operations for on large arrays/numbers.
"""
Power check if a number is a power of 2
Negative numbers are not allowed
"""
import math
def is_power_of_two(num):
"""
:type num: integer
"""
try:
x=0
x = math.log10(num)/math.log10(2)
return 2 ** x == num
except ValueError:
exit()
You can just use the power of the math library
import math
def isPowerOfTwo(n):
if n <= 0:
return False
res = int(math.log(n) / math.log(2))
return 2 ** res == n
This was my solution for a function which checks which number is a base of another:
def is_power_of(number, base):
# when number is smaller than base.
if base <= 1:
return False
elif number < base:
return False
elif number > base:
# keep dividing number by base.
return is_power_of(number/base, base)
else:
return True
This will be bit informative,
counter = 0
def powoftwo(n):
global counter
counter+=1
if n%2 != 0:
return "Given Number %s is not Power of 2!"%g
else:
if n==2:
return "yes give number %s = 2**%s is power of 2!"%(g, counter)
return powoftwo(n/2)
g = 1024
print powoftwo(g)
yes give number 1024 = 2**10 is power of 2!
Late to the party, though yet, another way:
import math
def is_power_of_2(x):
n = math.log(abs(x), 2)
return n == int(n)
Related
While practicing recursion I came across a question to reverse an integer using recursion. I tried to do the question without converting the integer into a string.
I was able to solve the question partially but the output would always come without any of the zeroes from the original input. Below is the code I came up with:
def reverseNumber(n):
if (n//10) == 0:
return n
lastDigit = n%10
ans = reverseNumber(n//10)
nod = 0
for i in str(ans):
nod += 1
return (10**nod)*lastDigit + ans
Upon inspection I could see that this was happening because when lastDigit is 0 it only returned the reversed integer from the recursive call i.e input 4230 will give 324.
But this also meant that all zeroes between the original input would also get removed as we went deeper in the recursive calls.
So please tell me how to modify this code so that zeroes in the original input are not removed while reversing.
You probably need just this:
def rev(n):
if n>0:
return str(n%10)+rev(n//10)
else:
return ''
reverseNumber should return an int and accept positive and negative numbers.
The simplest way to fix your code, without handling negative numbers, is:
def reverseNumber(n):
if n == 0:
return 0
lastDigit = n%10
n //= 10
return int(str(lastDigit) + str(reverseNumber(n))) if n else lastDigit
for test in (0, 123, 120):
print(test, reverseNumber(test))
Prints:
0 0
123 321
120 21
Yes! The reverse of 120 is 21 when you are dealing with int types as opposed to str types.
Another implementation that does handle negative numbers takes a whole different approach:
I have broken this out into two functions. Function rev is a generator function that assumes that it is being called with a positive, non-negative number and will recursively yield successive digits of the number in reverse. reverseNumber will join these numbers, convert to an int, adjust the sign and return the final result.
def reverseNumber(n):
def rev(n):
assert n >= 0
yield str(n % 10)
n //= 10
if n != 0:
yield from rev(n)
if n == 0: return 0 # special case
x = int(''.join(rev(abs(n))))
return x if n >= 0 else -x
tests = [0, 132, -132, 120]
for test in tests:
print(test, reverseNumber(test))
Prints:
0 0
132 231
-132 -231
120 21
For all non-negative n, when n < 10 it is a single digit and already the same as its reverse -
def reverse(n = 0):
if n < 10:
return str(n)
else
return str(n%10) + rev(n//10)
you can also try the following Python3 code. It will cover positive and negative integers to be reversed as integers - not as strings ...
x = int(input("What integer shall be reversed? "))
n = abs(x) # ... to handle negative integers
r = 0 # ... will hold the reversed int.
while n > 0: # Recursion part reversing int.
r = (r * 10) + (n % 10) # using '%' modulo
n = int(n / 10) # and a 'dirty way' to floor
if x < 0: # Turn result neg. if x was neg.
return (r * -1)
else:
return r # Keep result pos. if x was pos.
This approach will leave your zeros in the middle of the integer intact, though it will make any zero at the end of the initial number vanish - rightfully so as integers do not start with a zero. ;))
I am doing this project on udemy and I have compared my code to the solution but they do not match at all. Can someone tell me what the most efficient line of code would look like for this problem (collatz_conjecture)?
def collatz(n):
if n > 1 and n %2 == 0:
return (n/2)
elif n > 1 and n %2 != 0:
return (n*3+1)
print(collatz(3))
What your code is doing is that If the number is greater than 1 and is even, return the number after dividing it by 2, else if it is greater than 1 and odd, multiply the number by 3, add 1 to it and return.
For 3, the answer will be 10, since 3 is odd and 3*3+1=10. For 4 answer will be 2 since 4 is even and 4/2=2
Also from the wiki definition and your question, seems like you want to verify collatz conjecture, for which you need recursion to finally reach 1 for any positive integer, which can be done like so. Note the integer division n//2 to ensure we pass integer for every recursive call
def collatz(n):
#If n reaches 1 return it
if n == 1:
return 1
#Based on n being even or odd, call the function recursively
if n %2 == 0:
return collatz(n//2)
else:
return collatz(n*3+1)
print(collatz(3))
#1
print(collatz(33))
#1
I need to write a code that asks the user for a range of integers and then calculates which integers in that range have at least 3 factors (excluding 1 and the integer itself). I don't know how to take into consideration the fact that an integer can have multiple same factors, for example, in my code integer 8 returns a false value because the program divides it into two integers, 2 and 4. I want the return value to be true, because 8 can be divided into three factors of 2. How do i fix it?
def does_integer_have_3_or_more_factors(x):
num_of_factors = 0
for i in range(2, x):
if x % i == 0:
num_of_factors += 1
if num_of_factors >= 3 :
return True
else :
return False
def main():
integer1 = int(input("Give first positive integer.\n"))
integer2 = int(input("Give last integer.\n"))
print("These integers have at least 3 factors.")
for x in range(integer1, integer2 + 1):
if does_integer_have_3_or_more_factors(x) == True:
print(x)
main()
You need to use the factors you found, and apply them as often as necessary. Maybe you also want to keep track of the factors you found.
factors = []
...
for ... # see below
while x > 1 and not x%i:
factors.append(i)
x /= i
You can also stop checking for factors after sqrt(x) has been reached.
from math import sqrt
for i in range(2,int(sqrt(x))+1):
Finally, you're handling booleans in an overly complicated way. Just do
return len(factors) > 2 # "len(factors) > 2" will result in True or False directly
and check for
if does_integer_have_3_or_more_factors(x):
print(x)
I have to write a function to find if a given number (num) within 2 of a multiple of 10. I use modulus (%) to get the remainder, but it doesn't seem to be working quite right. Help?
def nearten(num):
if num%10<=2:
return True
elif num%10>2:
return False
Most of all, you only checked to see whether the "ones" digit is 0, 1, or 2 -- you missed 8 and 9.
As a styling note, don't check a boolean expression and then hard-code the result you just found. Your function, as currently written, reduces to this:
def nearten(num):
return num%10 <= 2
Do you see how that works? First of all, the elif check doesn't give you any new information: you already know that the result must be >2 when you get past the if condition.
Then, your statement reads like
if this condition is true, return true
otherwise, we know it's false; return false.
That's redundant. You have a True/False value sitting right in your program's hand -- just return that one, instead of using a constant.
REPAIR ...
I'll leave this as an exercise for the student: "within" 2 means that you have to check both sides, so you have to pick up the cases where the ones digit is 8 or 9. Can you write the expression to do that?
You can use Ternary operator and check for if num is within 2 of multiple of 10:
def near_ten(num):
return True if num%10<3 or num%10>7 else False
You can write this code as:
def near_ten(num):
a = num % 10
return 2 >= a or 8 <= a
Here is a little help:
def near_ten(num):
return num % 10 in [0,1,2,8,9,10]`
can also be:
return 0 <= (num % 10) <= 2 or 8 <= (num % 10) <= 10
This works:
def near_ten(num):
return num%10 <= 2 or num%10 >= (10 - 2 )
This method also works, just returning a bool value by using comparison operators in a single line to check both 'sides' of the cases:
def near_ten(num):
return (num % 10 <= 2 or num % 10 >= 8)
def near_ten(num):
if num%10<=2 :
return True
elif num%10 >=8:
return True
else:
return False
Given any random integer, create a function to find the next number that is a prime number and also a palindrome.
My attempt
def golf(number):
x = number + 1
for i in range(2, x):
if x % i == 0 or str(x) != str(x)[::-1]:
golf(number + 1)
return x
E.g golf(13) = 101
I'm actually looking for an alternative option than the recursion method i used. How can this best be accomplished without using recursion?
Thanks
Here's a variation on byron he's answer which adds several optimizations:
We can eliminate all even x values (other than 2) before doing any elaborate tests, since we can trivially tell they are not prime.
A small improvement is to only call str(x) once, and reuse the value later.
We can take advantage of the fact that all even-length palindromes are multiples of 11, which means that (except for 11 itself) they're not prime. We can jump ahead to the next odd-length x value.
Since we've already eliminated even numbers, our prime test only needs to test odd divisors. Further we can stop our loop when we reach sqrt(x), rather than going all the way to x itself.
Finally, there's no need to use a Boolean flag variable to carry the primeness out of the loop. If we don't break, the else block attached to the loop will be run.
The code:
import math
def next_prime_palindrome(x):
while True:
x += 1
if x > 2 and x % 2 == 0: # even numbers greater than 2 are non-prime
continue
s = str(x) # compute str(x) just once
if x > 11 and len(s) % 2 == 0: # all even-length palindromes are multiples of 11
x = 10 ** len(s) # so jump to the next odd-length integer
continue
if s != s[::-1]: # palindrome test
continue
for i in xrange(3, round(math.sqrt(x))+1, 2): # loop over odd potential divisors
if x % i == 0: # prime test
break
else: # this else block runs only if no break happened in the loop, so x is prime
return x
Here are some tests runs, showing a few cases where the optimizations save significant time:
>>> next_prime_palindrome(1)
2
>>> next_prime_palindrome(3)
5
>>> next_prime_palindrome(9)
11
>>> next_prime_palindrome(11)
101
>>> next_prime_palindrome(99999)
1003001
>>> next_prime_palindrome(999999999)
10000500001
A further improvement might be to directly generate palindromes, rather than working with integers to start with, and doing a palindrome test to filter them. That would get quite a bit further from your original design, so I'll leave that for someone else.
Palindrome are a sparser set of numbers than primes, and you can generate palindromes directly.
Consider the sequence 98.102
These are palidrome numbers you can base on these
989, 9889, 999, 9999, 10001, 100001, 10101, 101101, 10201, 102201
ADDED
Not also that all of the palidromes with an odd number of digits will come before the palidromes with an even number of digits.
If you write this as a generator (ie using yield) get get a straightforward algorithm for generating palindromic numbers in order.
For 1..9 you generate either 9 or 18 palindromes depending upon whether you consider 1 digit numbers palindromic.
For 10..99 you generate 90 even digit and 90 odd digit palindromes.
For 100..999 you generate 900 even digit and 900 odd digit palindromes.
You have just generated all 1989 (or 1997 if including single digit numbers) of the palindromic numbers less than 1 million. There are 78,498 primes less than 1 million
Any algorithm that is based on generating primes then testing for a palindrome will be much slower that generating palindromes and then testing for primes
def golf(number):
primes = []
i = 2
while i <= number:
if isPrime(i, primes):
primes.append(i)
i += 1
answer = primes[-1] + 1
while True:
if isPrime(answer, primes):
primes.append(answer)
if str(answer) == str(answer)[::-1]:
return answer
answer += 1
def isPrime(n, primes):
for (p for p in primes if p<=n**0.5):
if n%p == 0:
return False
return True
Your solution can be slightly modified in order to create an iterative solution:
def golf(number):
x = number + 1
while True:
is_golf = True
for i in range(2, x):
if x % i == 0 or str(x) != str(x)[::-1]:
is_golf = False
break
if is_golf:
return x
x += 1
improved according to Blckknght's advice, thanks.
def golf(number):
x = number
while True:
x += 1
if str(x) != str(x)[::-1]:
continue
for i in xrange(2, x):
if x % i == 0 :
break
else:
return x