Check if a given number N is a power of k
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
7
down vote
favorite
I am trying to solve a problem to check whether a given number N is a power of k.
Example:
- Input 9, 3 > True // 3**2 = 9
- Input 10, 2 > False
- Input 4096, 16 > True // 16**3 = 4096
I want to know if there is a better solution for this problem.
def check_Power(N,k):
if N <= 0 or k <=0:
print "not a valid input"
else:
for i in range (1,20):
x = k**i
if x == N :
print " True "
print k, "power ", i , "is", N
break
elif x> N:
print "false"
break
check_Power(244140625,5)
check_Power(4096, 16)
check_Power(0, 16)
check_Power(1,1)
python mathematics
add a comment |Â
up vote
7
down vote
favorite
I am trying to solve a problem to check whether a given number N is a power of k.
Example:
- Input 9, 3 > True // 3**2 = 9
- Input 10, 2 > False
- Input 4096, 16 > True // 16**3 = 4096
I want to know if there is a better solution for this problem.
def check_Power(N,k):
if N <= 0 or k <=0:
print "not a valid input"
else:
for i in range (1,20):
x = k**i
if x == N :
print " True "
print k, "power ", i , "is", N
break
elif x> N:
print "false"
break
check_Power(244140625,5)
check_Power(4096, 16)
check_Power(0, 16)
check_Power(1,1)
python mathematics
1
ForN
to be a multiple ofk
it must be not less thank
and must give an integer result when divided byk
. If it is a power ofk
then the result of division must be either1
of a multiple ofk
. So, you can just iterate dividingN
byk
as long asN
is greater or equalk
. Then, if it became1
, the initial value was a power ofk
, otherwise it wasn't.
â CiaPan
Jan 4 at 10:18
One more note: test fork
equal1
â no number (except1
itself) can be a power of1
...
â CiaPan
Jan 4 at 10:20
Duplicate of codereview.stackexchange.com/questions/160924/⦠?
â dberm22
Jan 5 at 13:57
add a comment |Â
up vote
7
down vote
favorite
up vote
7
down vote
favorite
I am trying to solve a problem to check whether a given number N is a power of k.
Example:
- Input 9, 3 > True // 3**2 = 9
- Input 10, 2 > False
- Input 4096, 16 > True // 16**3 = 4096
I want to know if there is a better solution for this problem.
def check_Power(N,k):
if N <= 0 or k <=0:
print "not a valid input"
else:
for i in range (1,20):
x = k**i
if x == N :
print " True "
print k, "power ", i , "is", N
break
elif x> N:
print "false"
break
check_Power(244140625,5)
check_Power(4096, 16)
check_Power(0, 16)
check_Power(1,1)
python mathematics
I am trying to solve a problem to check whether a given number N is a power of k.
Example:
- Input 9, 3 > True // 3**2 = 9
- Input 10, 2 > False
- Input 4096, 16 > True // 16**3 = 4096
I want to know if there is a better solution for this problem.
def check_Power(N,k):
if N <= 0 or k <=0:
print "not a valid input"
else:
for i in range (1,20):
x = k**i
if x == N :
print " True "
print k, "power ", i , "is", N
break
elif x> N:
print "false"
break
check_Power(244140625,5)
check_Power(4096, 16)
check_Power(0, 16)
check_Power(1,1)
python mathematics
edited May 23 at 6:00
asked Jan 4 at 9:20
Latika Agarwal
861216
861216
1
ForN
to be a multiple ofk
it must be not less thank
and must give an integer result when divided byk
. If it is a power ofk
then the result of division must be either1
of a multiple ofk
. So, you can just iterate dividingN
byk
as long asN
is greater or equalk
. Then, if it became1
, the initial value was a power ofk
, otherwise it wasn't.
â CiaPan
Jan 4 at 10:18
One more note: test fork
equal1
â no number (except1
itself) can be a power of1
...
â CiaPan
Jan 4 at 10:20
Duplicate of codereview.stackexchange.com/questions/160924/⦠?
â dberm22
Jan 5 at 13:57
add a comment |Â
1
ForN
to be a multiple ofk
it must be not less thank
and must give an integer result when divided byk
. If it is a power ofk
then the result of division must be either1
of a multiple ofk
. So, you can just iterate dividingN
byk
as long asN
is greater or equalk
. Then, if it became1
, the initial value was a power ofk
, otherwise it wasn't.
â CiaPan
Jan 4 at 10:18
One more note: test fork
equal1
â no number (except1
itself) can be a power of1
...
â CiaPan
Jan 4 at 10:20
Duplicate of codereview.stackexchange.com/questions/160924/⦠?
â dberm22
Jan 5 at 13:57
1
1
For
N
to be a multiple of k
it must be not less than k
and must give an integer result when divided by k
. If it is a power of k
then the result of division must be either 1
of a multiple of k
. So, you can just iterate dividing N
by k
as long as N
is greater or equal k
. Then, if it became 1
, the initial value was a power of k
, otherwise it wasn't.â CiaPan
Jan 4 at 10:18
For
N
to be a multiple of k
it must be not less than k
and must give an integer result when divided by k
. If it is a power of k
then the result of division must be either 1
of a multiple of k
. So, you can just iterate dividing N
by k
as long as N
is greater or equal k
. Then, if it became 1
, the initial value was a power of k
, otherwise it wasn't.â CiaPan
Jan 4 at 10:18
One more note: test for
k
equal 1
â no number (except 1
itself) can be a power of 1
...â CiaPan
Jan 4 at 10:20
One more note: test for
k
equal 1
â no number (except 1
itself) can be a power of 1
...â CiaPan
Jan 4 at 10:20
Duplicate of codereview.stackexchange.com/questions/160924/⦠?
â dberm22
Jan 5 at 13:57
Duplicate of codereview.stackexchange.com/questions/160924/⦠?
â dberm22
Jan 5 at 13:57
add a comment |Â
6 Answers
6
active
oldest
votes
up vote
14
down vote
accepted
Major
print " True "
- Don't print but
return
variables from functions, that makes them usable later on
print "not a valid input"
- You should
raise
an Exception with invalid input instead of printing it
for i in range (1,20):
- This line will limit the input range from the function
if N <= 0 or k <=0:
- Your guard clause does not cover all edge cases
Minor
- Use better variable names,
x
doesn't say much - That
else
block is redundant, yourif
actually is a guard clause, remove the redundant indenting. - You have a few PEP8 issues
Revised code
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater than 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
num = k
while num < N:
num *= k
return num == N
1
Still not safe â verifycheck_pow (4, 1)
.
â CiaPan
Jan 4 at 10:58
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
1
Replacegreater then
withgreater than
â Olivier Grégoire
Jan 4 at 15:54
2
num
isn't any more meaningful thanx
.
â amalloy
Jan 4 at 19:27
1
Nothing. I thinkx
was perfectly fine. But a more meaningful name would be something likeproduct
, or perhapsacc
.
â amalloy
Jan 4 at 22:03
 |Â
show 2 more comments
up vote
17
down vote
I'd follow Ludisposed's answer.
Except, there's a simple way to do this. Use logarithms.
Since the equation is $N = k^a$ you can change it to $a = log_k N$.
And so if $a$ is an integer, then you know that $N$ is a power of $k$.
import math
def check_power(N, k):
return math.log(N, k).is_integer()
Since the above can error, and if there's an error it's definately not a power, then you can use:
def check_power(N, k):
try:
return math.log(N, k).is_integer()
except Exception:
return False
This has the some problems with floating point precision, so your can round the number to the closest integer, as you want to know if the $a$ is an integer. And so you can sub it back into the original equation to ensure that the numbers are right.
def check_power(N, k):
return N == k**round(math.log(N, k))
Or if you're on Python 2:
def check_power(N, k):
return N == k**int(round(math.log(N, k)))
This has a problem with some inputs, such as when $N$ and $k$ are $0$ or $1$. And so we can handle these special cases.
def check_power(N, k):
if N == k:
return True
return N == k**round(math.log(N, k))
And so merging all the above, we can use the following:
def check_power(N, k):
if N == k:
return True
try:
return N == k**int(round(math.log(N, k)))
except Exception:
return False
You still need special cases forN == 0 or k in 0, 1
.
â Veedrac
Jan 4 at 17:25
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
2
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,check_power(1, 1)
is wrong.
â Veedrac
Jan 4 at 17:33
@Veedrac Maybe the easiest fix for this would beif N == k: return True
.
â Graipher
Jan 5 at 10:28
add a comment |Â
up vote
3
down vote
I recommend @Ludisposed's answer for the Pythonic comments.
The algorithm itself can be improved to get logarithmic complexity (ie, a logarithmic number of multiplies and comparisons).
The idea is to use:
- A galloping search to locate the two powers of 2 between which logk(N) would be if N was a power of 2.
- A binary search between the last smaller power of 2 and its successor to locate the exact exponent.
Visualizing it in code may be easier:
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater then 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
powers = [1, k] # powers[i] = k ** (2**i)
# Galloping search:
# With e = log-k(N),
# find a and b such that 2**a <= e < 2**b
while powers[-1] < N:
powers.append(powers[-1] * powers[-1])
# Binary search:
# Narrow down the gap to find the closest power of k
# that is <= to N.
powers.pop()
cursor = powers.pop()
while len(powers) > 0:
candidate = cursor * powers.pop()
if candidate <= N:
cursor = candidate
return cursor == N
There are minor performance improvements possible still, short-circuitings notably, however they do not improve the worst-case complexity so I left them out to avoid mucking the algorithm.
add a comment |Â
up vote
3
down vote
This answer will focus on cleaning up the algorithm you used although, as other answers have shown, there are better algorithms for this problem. I will also answer how to loop over the infinite list of natural numbers with a generator. (Although I will refer to these as the counting numbers to clarify that I am not including 0.)
"Flat is better than nested"
An if statement that is checking a precondition for a function should avoid else
because the else makes the entire function more deeply nested and adds little to the understandability when it is clear that the if statement is there to check if the provided arguments are valid.
Misc
I recommend returning True
or False
instead of printing so that you can reuse this function in later problems. As a slight benefit, returning a value also removes the need for break
.
I also recommend using from __future__ import print_function
so that you can be forwards compatible with Python3. Note that you will have to use parentheses with print
and the new version below doesn't use print so this was left out of the code below.
Generators
Answering your question about how to loop over all the counting numbers, you could use a while loop or you could use generators. To show what your code might look like with a generator, see the following.
def counting_numbers():
i = 1
while True:
yield i
i += 1
def check_power(N, k):
# Note that you could include 0 if you're careful about it.
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# We need to catch 1 as a special case because 1 ** n = 1 for all n
# and thus 1 ** n will never be greater than N causing an infinite loop
if k == 1: # If the power is one
return N == 1 # Then N is a power only if it is 1
for i in counting_numbers():
x = k ** i
if x == N :
return True
elif x > N:
return False
As you can see, you write what looks like a normal function and then use yield
wherever you want to give a value to the for loop. The generator you are writing will yield control over to the loop whenever it hits a yield statement which is why this generator doesn't cause the program to seize up in an infinite loop. You can read more about generators in their original PEP 255 or in various online tutorials. Just know that they will stop upon hitting the end of their block like a function would or a return
statement. (Sidenote: don't try using return x
in a generator, this is related to sending a StopIteration
and doesn't make the generator return a value like you might expect.)
In this case, we actually don't have to write counting_numbers
because itertools
already has this builtin as itertools.count
but because we want to start from 1 instead of 0 we will have to call count(1)
instead of count()
which would start from 0. We can now rewrite the above solution to
from itertools import count
def check_power(N, k):
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# This special case is to avoid an infinite loop
if k == 1:
return N == 1
for i in count(1):
x = k ** i
if x == N :
return True
elif x > N:
return False
add a comment |Â
up vote
0
down vote
This can be done without looping. The idea is to rearrange
$$N=k^c$$
to
$$c = log_k N = fraclog Nlog k.$$
If the exponent is an integer, then it is a perfect power. In the below code, some extra work is done to avoid floating-point rounding errors.
import math
def check_Power(N,k):
# input validation
if N < 0:
raise Exception('N must be non-negative')
if k < 0:
raise Exception('k must be non-negative')
# 1 to any power can only equal 1
if k == 1:
return N == 1
# Only raising 0 to a non-zero power results in zero
if N == 0 or k == 0:
return k == N
# Use math.floor to make the exponent an integer
# that is within 1 of the actual answer
exponent = math.floor(math.log(N)/math.log(k))
# Test whether the integer exponent solves
# the problem and adjust the exponent as needed
testN = k**exponent
if testN < N:
exponent += 1
elif testN > N:
exponent -= 1
else:
return True # testN == N
return k**exponent == N # check adjusted exponent
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
add a comment |Â
up vote
0
down vote
I'm going to assume you mean integers since that's what your test data suggests. I'm also assuming the powers are non-negative integers so as not to involve roots (a).
In that case, there's no need to do all those power calculations, you just need to realise that, if n
is a power of k
, then continuously multiplying an accumulator (initially k
) by k
will either:
- reach
n
exactly (if it's a power). - exceed
n
(if it's not a power).
never satisfy either of those conditions because the accumulator never gets any closer ton
(see below code for those conditions).
In any case, the code you have only checks if n
is a power of k
with an exponent less than or equal to twenty, it won't return true for k = 2, n = 2**31
for example.
The code to do it a a less limited way is a stunningly simple:
def isPower(n, k):
# Special cases.
if k == 0: return n == 0 # 0^not-0 always 0, 0^0 undefined
if k == 1: return n == 1 # 1^n always 1
if k == -1: return abs(n) == 1 # -1^n alternates +/-1
# abs(k) is now >= 2 so it will always increase in magnitude.
acc = k
while abs(acc) < abs(n):
acc = acc * k
return acc == n
(a) If you decide to use floating point values, it gets a little more complicated. You then have to cater for more possibilities:
- if the power is allowed to be fractional, you'll have to cater for roots as well as powers;
- where
k
is be between -1 and 1, it will always approach zero rather than getting larger, so you'll need to adapt for that; - the adaptation for that must also take into account whether
n
is in that range or whether its absolute value is greater than or equal to one;
There's may well be other issues that haven't sprung immediately to mind, I won't think too much about them as, in the absence of further information, they're probably unnecessary.
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
For which negative input? YourisPower(-8, -2)
returns False.
â Martin R
Jan 5 at 7:03
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
YourisPower(1, -1)
returns False.
â Martin R
Jan 5 at 7:55
 |Â
show 2 more comments
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
14
down vote
accepted
Major
print " True "
- Don't print but
return
variables from functions, that makes them usable later on
print "not a valid input"
- You should
raise
an Exception with invalid input instead of printing it
for i in range (1,20):
- This line will limit the input range from the function
if N <= 0 or k <=0:
- Your guard clause does not cover all edge cases
Minor
- Use better variable names,
x
doesn't say much - That
else
block is redundant, yourif
actually is a guard clause, remove the redundant indenting. - You have a few PEP8 issues
Revised code
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater than 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
num = k
while num < N:
num *= k
return num == N
1
Still not safe â verifycheck_pow (4, 1)
.
â CiaPan
Jan 4 at 10:58
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
1
Replacegreater then
withgreater than
â Olivier Grégoire
Jan 4 at 15:54
2
num
isn't any more meaningful thanx
.
â amalloy
Jan 4 at 19:27
1
Nothing. I thinkx
was perfectly fine. But a more meaningful name would be something likeproduct
, or perhapsacc
.
â amalloy
Jan 4 at 22:03
 |Â
show 2 more comments
up vote
14
down vote
accepted
Major
print " True "
- Don't print but
return
variables from functions, that makes them usable later on
print "not a valid input"
- You should
raise
an Exception with invalid input instead of printing it
for i in range (1,20):
- This line will limit the input range from the function
if N <= 0 or k <=0:
- Your guard clause does not cover all edge cases
Minor
- Use better variable names,
x
doesn't say much - That
else
block is redundant, yourif
actually is a guard clause, remove the redundant indenting. - You have a few PEP8 issues
Revised code
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater than 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
num = k
while num < N:
num *= k
return num == N
1
Still not safe â verifycheck_pow (4, 1)
.
â CiaPan
Jan 4 at 10:58
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
1
Replacegreater then
withgreater than
â Olivier Grégoire
Jan 4 at 15:54
2
num
isn't any more meaningful thanx
.
â amalloy
Jan 4 at 19:27
1
Nothing. I thinkx
was perfectly fine. But a more meaningful name would be something likeproduct
, or perhapsacc
.
â amalloy
Jan 4 at 22:03
 |Â
show 2 more comments
up vote
14
down vote
accepted
up vote
14
down vote
accepted
Major
print " True "
- Don't print but
return
variables from functions, that makes them usable later on
print "not a valid input"
- You should
raise
an Exception with invalid input instead of printing it
for i in range (1,20):
- This line will limit the input range from the function
if N <= 0 or k <=0:
- Your guard clause does not cover all edge cases
Minor
- Use better variable names,
x
doesn't say much - That
else
block is redundant, yourif
actually is a guard clause, remove the redundant indenting. - You have a few PEP8 issues
Revised code
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater than 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
num = k
while num < N:
num *= k
return num == N
Major
print " True "
- Don't print but
return
variables from functions, that makes them usable later on
print "not a valid input"
- You should
raise
an Exception with invalid input instead of printing it
for i in range (1,20):
- This line will limit the input range from the function
if N <= 0 or k <=0:
- Your guard clause does not cover all edge cases
Minor
- Use better variable names,
x
doesn't say much - That
else
block is redundant, yourif
actually is a guard clause, remove the redundant indenting. - You have a few PEP8 issues
Revised code
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater than 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
num = k
while num < N:
num *= k
return num == N
edited Jan 4 at 17:31
answered Jan 4 at 10:31
Ludisposed
5,82821758
5,82821758
1
Still not safe â verifycheck_pow (4, 1)
.
â CiaPan
Jan 4 at 10:58
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
1
Replacegreater then
withgreater than
â Olivier Grégoire
Jan 4 at 15:54
2
num
isn't any more meaningful thanx
.
â amalloy
Jan 4 at 19:27
1
Nothing. I thinkx
was perfectly fine. But a more meaningful name would be something likeproduct
, or perhapsacc
.
â amalloy
Jan 4 at 22:03
 |Â
show 2 more comments
1
Still not safe â verifycheck_pow (4, 1)
.
â CiaPan
Jan 4 at 10:58
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
1
Replacegreater then
withgreater than
â Olivier Grégoire
Jan 4 at 15:54
2
num
isn't any more meaningful thanx
.
â amalloy
Jan 4 at 19:27
1
Nothing. I thinkx
was perfectly fine. But a more meaningful name would be something likeproduct
, or perhapsacc
.
â amalloy
Jan 4 at 22:03
1
1
Still not safe â verify
check_pow (4, 1)
.â CiaPan
Jan 4 at 10:58
Still not safe â verify
check_pow (4, 1)
.â CiaPan
Jan 4 at 10:58
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
@CiaPan All edge cases are now accounted for
â Ludisposed
Jan 4 at 12:27
1
1
Replace
greater then
with greater than
â Olivier Grégoire
Jan 4 at 15:54
Replace
greater then
with greater than
â Olivier Grégoire
Jan 4 at 15:54
2
2
num
isn't any more meaningful than x
.â amalloy
Jan 4 at 19:27
num
isn't any more meaningful than x
.â amalloy
Jan 4 at 19:27
1
1
Nothing. I think
x
was perfectly fine. But a more meaningful name would be something like product
, or perhaps acc
.â amalloy
Jan 4 at 22:03
Nothing. I think
x
was perfectly fine. But a more meaningful name would be something like product
, or perhaps acc
.â amalloy
Jan 4 at 22:03
 |Â
show 2 more comments
up vote
17
down vote
I'd follow Ludisposed's answer.
Except, there's a simple way to do this. Use logarithms.
Since the equation is $N = k^a$ you can change it to $a = log_k N$.
And so if $a$ is an integer, then you know that $N$ is a power of $k$.
import math
def check_power(N, k):
return math.log(N, k).is_integer()
Since the above can error, and if there's an error it's definately not a power, then you can use:
def check_power(N, k):
try:
return math.log(N, k).is_integer()
except Exception:
return False
This has the some problems with floating point precision, so your can round the number to the closest integer, as you want to know if the $a$ is an integer. And so you can sub it back into the original equation to ensure that the numbers are right.
def check_power(N, k):
return N == k**round(math.log(N, k))
Or if you're on Python 2:
def check_power(N, k):
return N == k**int(round(math.log(N, k)))
This has a problem with some inputs, such as when $N$ and $k$ are $0$ or $1$. And so we can handle these special cases.
def check_power(N, k):
if N == k:
return True
return N == k**round(math.log(N, k))
And so merging all the above, we can use the following:
def check_power(N, k):
if N == k:
return True
try:
return N == k**int(round(math.log(N, k)))
except Exception:
return False
You still need special cases forN == 0 or k in 0, 1
.
â Veedrac
Jan 4 at 17:25
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
2
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,check_power(1, 1)
is wrong.
â Veedrac
Jan 4 at 17:33
@Veedrac Maybe the easiest fix for this would beif N == k: return True
.
â Graipher
Jan 5 at 10:28
add a comment |Â
up vote
17
down vote
I'd follow Ludisposed's answer.
Except, there's a simple way to do this. Use logarithms.
Since the equation is $N = k^a$ you can change it to $a = log_k N$.
And so if $a$ is an integer, then you know that $N$ is a power of $k$.
import math
def check_power(N, k):
return math.log(N, k).is_integer()
Since the above can error, and if there's an error it's definately not a power, then you can use:
def check_power(N, k):
try:
return math.log(N, k).is_integer()
except Exception:
return False
This has the some problems with floating point precision, so your can round the number to the closest integer, as you want to know if the $a$ is an integer. And so you can sub it back into the original equation to ensure that the numbers are right.
def check_power(N, k):
return N == k**round(math.log(N, k))
Or if you're on Python 2:
def check_power(N, k):
return N == k**int(round(math.log(N, k)))
This has a problem with some inputs, such as when $N$ and $k$ are $0$ or $1$. And so we can handle these special cases.
def check_power(N, k):
if N == k:
return True
return N == k**round(math.log(N, k))
And so merging all the above, we can use the following:
def check_power(N, k):
if N == k:
return True
try:
return N == k**int(round(math.log(N, k)))
except Exception:
return False
You still need special cases forN == 0 or k in 0, 1
.
â Veedrac
Jan 4 at 17:25
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
2
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,check_power(1, 1)
is wrong.
â Veedrac
Jan 4 at 17:33
@Veedrac Maybe the easiest fix for this would beif N == k: return True
.
â Graipher
Jan 5 at 10:28
add a comment |Â
up vote
17
down vote
up vote
17
down vote
I'd follow Ludisposed's answer.
Except, there's a simple way to do this. Use logarithms.
Since the equation is $N = k^a$ you can change it to $a = log_k N$.
And so if $a$ is an integer, then you know that $N$ is a power of $k$.
import math
def check_power(N, k):
return math.log(N, k).is_integer()
Since the above can error, and if there's an error it's definately not a power, then you can use:
def check_power(N, k):
try:
return math.log(N, k).is_integer()
except Exception:
return False
This has the some problems with floating point precision, so your can round the number to the closest integer, as you want to know if the $a$ is an integer. And so you can sub it back into the original equation to ensure that the numbers are right.
def check_power(N, k):
return N == k**round(math.log(N, k))
Or if you're on Python 2:
def check_power(N, k):
return N == k**int(round(math.log(N, k)))
This has a problem with some inputs, such as when $N$ and $k$ are $0$ or $1$. And so we can handle these special cases.
def check_power(N, k):
if N == k:
return True
return N == k**round(math.log(N, k))
And so merging all the above, we can use the following:
def check_power(N, k):
if N == k:
return True
try:
return N == k**int(round(math.log(N, k)))
except Exception:
return False
I'd follow Ludisposed's answer.
Except, there's a simple way to do this. Use logarithms.
Since the equation is $N = k^a$ you can change it to $a = log_k N$.
And so if $a$ is an integer, then you know that $N$ is a power of $k$.
import math
def check_power(N, k):
return math.log(N, k).is_integer()
Since the above can error, and if there's an error it's definately not a power, then you can use:
def check_power(N, k):
try:
return math.log(N, k).is_integer()
except Exception:
return False
This has the some problems with floating point precision, so your can round the number to the closest integer, as you want to know if the $a$ is an integer. And so you can sub it back into the original equation to ensure that the numbers are right.
def check_power(N, k):
return N == k**round(math.log(N, k))
Or if you're on Python 2:
def check_power(N, k):
return N == k**int(round(math.log(N, k)))
This has a problem with some inputs, such as when $N$ and $k$ are $0$ or $1$. And so we can handle these special cases.
def check_power(N, k):
if N == k:
return True
return N == k**round(math.log(N, k))
And so merging all the above, we can use the following:
def check_power(N, k):
if N == k:
return True
try:
return N == k**int(round(math.log(N, k)))
except Exception:
return False
edited Jan 5 at 10:34
answered Jan 4 at 10:39
Peilonrayz
24.4k336102
24.4k336102
You still need special cases forN == 0 or k in 0, 1
.
â Veedrac
Jan 4 at 17:25
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
2
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,check_power(1, 1)
is wrong.
â Veedrac
Jan 4 at 17:33
@Veedrac Maybe the easiest fix for this would beif N == k: return True
.
â Graipher
Jan 5 at 10:28
add a comment |Â
You still need special cases forN == 0 or k in 0, 1
.
â Veedrac
Jan 4 at 17:25
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
2
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,check_power(1, 1)
is wrong.
â Veedrac
Jan 4 at 17:33
@Veedrac Maybe the easiest fix for this would beif N == k: return True
.
â Graipher
Jan 5 at 10:28
You still need special cases for
N == 0 or k in 0, 1
.â Veedrac
Jan 4 at 17:25
You still need special cases for
N == 0 or k in 0, 1
.â Veedrac
Jan 4 at 17:25
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
@Veedrac How do you mean? They raise exceptions, which are handled in the second code snippet above.
â Peilonrayz
Jan 4 at 17:29
2
2
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,
check_power(1, 1)
is wrong.â Veedrac
Jan 4 at 17:33
@Peilonrayz Ah, I was ignoring the earlier snippets since they're wrong, and just looking at the latter ones. Even in that case,
check_power(1, 1)
is wrong.â Veedrac
Jan 4 at 17:33
@Veedrac Maybe the easiest fix for this would be
if N == k: return True
.â Graipher
Jan 5 at 10:28
@Veedrac Maybe the easiest fix for this would be
if N == k: return True
.â Graipher
Jan 5 at 10:28
add a comment |Â
up vote
3
down vote
I recommend @Ludisposed's answer for the Pythonic comments.
The algorithm itself can be improved to get logarithmic complexity (ie, a logarithmic number of multiplies and comparisons).
The idea is to use:
- A galloping search to locate the two powers of 2 between which logk(N) would be if N was a power of 2.
- A binary search between the last smaller power of 2 and its successor to locate the exact exponent.
Visualizing it in code may be easier:
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater then 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
powers = [1, k] # powers[i] = k ** (2**i)
# Galloping search:
# With e = log-k(N),
# find a and b such that 2**a <= e < 2**b
while powers[-1] < N:
powers.append(powers[-1] * powers[-1])
# Binary search:
# Narrow down the gap to find the closest power of k
# that is <= to N.
powers.pop()
cursor = powers.pop()
while len(powers) > 0:
candidate = cursor * powers.pop()
if candidate <= N:
cursor = candidate
return cursor == N
There are minor performance improvements possible still, short-circuitings notably, however they do not improve the worst-case complexity so I left them out to avoid mucking the algorithm.
add a comment |Â
up vote
3
down vote
I recommend @Ludisposed's answer for the Pythonic comments.
The algorithm itself can be improved to get logarithmic complexity (ie, a logarithmic number of multiplies and comparisons).
The idea is to use:
- A galloping search to locate the two powers of 2 between which logk(N) would be if N was a power of 2.
- A binary search between the last smaller power of 2 and its successor to locate the exact exponent.
Visualizing it in code may be easier:
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater then 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
powers = [1, k] # powers[i] = k ** (2**i)
# Galloping search:
# With e = log-k(N),
# find a and b such that 2**a <= e < 2**b
while powers[-1] < N:
powers.append(powers[-1] * powers[-1])
# Binary search:
# Narrow down the gap to find the closest power of k
# that is <= to N.
powers.pop()
cursor = powers.pop()
while len(powers) > 0:
candidate = cursor * powers.pop()
if candidate <= N:
cursor = candidate
return cursor == N
There are minor performance improvements possible still, short-circuitings notably, however they do not improve the worst-case complexity so I left them out to avoid mucking the algorithm.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
I recommend @Ludisposed's answer for the Pythonic comments.
The algorithm itself can be improved to get logarithmic complexity (ie, a logarithmic number of multiplies and comparisons).
The idea is to use:
- A galloping search to locate the two powers of 2 between which logk(N) would be if N was a power of 2.
- A binary search between the last smaller power of 2 and its successor to locate the exact exponent.
Visualizing it in code may be easier:
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater then 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
powers = [1, k] # powers[i] = k ** (2**i)
# Galloping search:
# With e = log-k(N),
# find a and b such that 2**a <= e < 2**b
while powers[-1] < N:
powers.append(powers[-1] * powers[-1])
# Binary search:
# Narrow down the gap to find the closest power of k
# that is <= to N.
powers.pop()
cursor = powers.pop()
while len(powers) > 0:
candidate = cursor * powers.pop()
if candidate <= N:
cursor = candidate
return cursor == N
There are minor performance improvements possible still, short-circuitings notably, however they do not improve the worst-case complexity so I left them out to avoid mucking the algorithm.
I recommend @Ludisposed's answer for the Pythonic comments.
The algorithm itself can be improved to get logarithmic complexity (ie, a logarithmic number of multiplies and comparisons).
The idea is to use:
- A galloping search to locate the two powers of 2 between which logk(N) would be if N was a power of 2.
- A binary search between the last smaller power of 2 and its successor to locate the exact exponent.
Visualizing it in code may be easier:
def check_pow(N, k):
if k < 0 or N < 0:
raise ValueError("k and N must be greater then 0")
if k == 0 and N == 1:
return True
if k in (0, 1) and N != 1:
return False
powers = [1, k] # powers[i] = k ** (2**i)
# Galloping search:
# With e = log-k(N),
# find a and b such that 2**a <= e < 2**b
while powers[-1] < N:
powers.append(powers[-1] * powers[-1])
# Binary search:
# Narrow down the gap to find the closest power of k
# that is <= to N.
powers.pop()
cursor = powers.pop()
while len(powers) > 0:
candidate = cursor * powers.pop()
if candidate <= N:
cursor = candidate
return cursor == N
There are minor performance improvements possible still, short-circuitings notably, however they do not improve the worst-case complexity so I left them out to avoid mucking the algorithm.
answered Jan 4 at 16:40
Matthieu M.
2,0821710
2,0821710
add a comment |Â
add a comment |Â
up vote
3
down vote
This answer will focus on cleaning up the algorithm you used although, as other answers have shown, there are better algorithms for this problem. I will also answer how to loop over the infinite list of natural numbers with a generator. (Although I will refer to these as the counting numbers to clarify that I am not including 0.)
"Flat is better than nested"
An if statement that is checking a precondition for a function should avoid else
because the else makes the entire function more deeply nested and adds little to the understandability when it is clear that the if statement is there to check if the provided arguments are valid.
Misc
I recommend returning True
or False
instead of printing so that you can reuse this function in later problems. As a slight benefit, returning a value also removes the need for break
.
I also recommend using from __future__ import print_function
so that you can be forwards compatible with Python3. Note that you will have to use parentheses with print
and the new version below doesn't use print so this was left out of the code below.
Generators
Answering your question about how to loop over all the counting numbers, you could use a while loop or you could use generators. To show what your code might look like with a generator, see the following.
def counting_numbers():
i = 1
while True:
yield i
i += 1
def check_power(N, k):
# Note that you could include 0 if you're careful about it.
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# We need to catch 1 as a special case because 1 ** n = 1 for all n
# and thus 1 ** n will never be greater than N causing an infinite loop
if k == 1: # If the power is one
return N == 1 # Then N is a power only if it is 1
for i in counting_numbers():
x = k ** i
if x == N :
return True
elif x > N:
return False
As you can see, you write what looks like a normal function and then use yield
wherever you want to give a value to the for loop. The generator you are writing will yield control over to the loop whenever it hits a yield statement which is why this generator doesn't cause the program to seize up in an infinite loop. You can read more about generators in their original PEP 255 or in various online tutorials. Just know that they will stop upon hitting the end of their block like a function would or a return
statement. (Sidenote: don't try using return x
in a generator, this is related to sending a StopIteration
and doesn't make the generator return a value like you might expect.)
In this case, we actually don't have to write counting_numbers
because itertools
already has this builtin as itertools.count
but because we want to start from 1 instead of 0 we will have to call count(1)
instead of count()
which would start from 0. We can now rewrite the above solution to
from itertools import count
def check_power(N, k):
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# This special case is to avoid an infinite loop
if k == 1:
return N == 1
for i in count(1):
x = k ** i
if x == N :
return True
elif x > N:
return False
add a comment |Â
up vote
3
down vote
This answer will focus on cleaning up the algorithm you used although, as other answers have shown, there are better algorithms for this problem. I will also answer how to loop over the infinite list of natural numbers with a generator. (Although I will refer to these as the counting numbers to clarify that I am not including 0.)
"Flat is better than nested"
An if statement that is checking a precondition for a function should avoid else
because the else makes the entire function more deeply nested and adds little to the understandability when it is clear that the if statement is there to check if the provided arguments are valid.
Misc
I recommend returning True
or False
instead of printing so that you can reuse this function in later problems. As a slight benefit, returning a value also removes the need for break
.
I also recommend using from __future__ import print_function
so that you can be forwards compatible with Python3. Note that you will have to use parentheses with print
and the new version below doesn't use print so this was left out of the code below.
Generators
Answering your question about how to loop over all the counting numbers, you could use a while loop or you could use generators. To show what your code might look like with a generator, see the following.
def counting_numbers():
i = 1
while True:
yield i
i += 1
def check_power(N, k):
# Note that you could include 0 if you're careful about it.
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# We need to catch 1 as a special case because 1 ** n = 1 for all n
# and thus 1 ** n will never be greater than N causing an infinite loop
if k == 1: # If the power is one
return N == 1 # Then N is a power only if it is 1
for i in counting_numbers():
x = k ** i
if x == N :
return True
elif x > N:
return False
As you can see, you write what looks like a normal function and then use yield
wherever you want to give a value to the for loop. The generator you are writing will yield control over to the loop whenever it hits a yield statement which is why this generator doesn't cause the program to seize up in an infinite loop. You can read more about generators in their original PEP 255 or in various online tutorials. Just know that they will stop upon hitting the end of their block like a function would or a return
statement. (Sidenote: don't try using return x
in a generator, this is related to sending a StopIteration
and doesn't make the generator return a value like you might expect.)
In this case, we actually don't have to write counting_numbers
because itertools
already has this builtin as itertools.count
but because we want to start from 1 instead of 0 we will have to call count(1)
instead of count()
which would start from 0. We can now rewrite the above solution to
from itertools import count
def check_power(N, k):
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# This special case is to avoid an infinite loop
if k == 1:
return N == 1
for i in count(1):
x = k ** i
if x == N :
return True
elif x > N:
return False
add a comment |Â
up vote
3
down vote
up vote
3
down vote
This answer will focus on cleaning up the algorithm you used although, as other answers have shown, there are better algorithms for this problem. I will also answer how to loop over the infinite list of natural numbers with a generator. (Although I will refer to these as the counting numbers to clarify that I am not including 0.)
"Flat is better than nested"
An if statement that is checking a precondition for a function should avoid else
because the else makes the entire function more deeply nested and adds little to the understandability when it is clear that the if statement is there to check if the provided arguments are valid.
Misc
I recommend returning True
or False
instead of printing so that you can reuse this function in later problems. As a slight benefit, returning a value also removes the need for break
.
I also recommend using from __future__ import print_function
so that you can be forwards compatible with Python3. Note that you will have to use parentheses with print
and the new version below doesn't use print so this was left out of the code below.
Generators
Answering your question about how to loop over all the counting numbers, you could use a while loop or you could use generators. To show what your code might look like with a generator, see the following.
def counting_numbers():
i = 1
while True:
yield i
i += 1
def check_power(N, k):
# Note that you could include 0 if you're careful about it.
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# We need to catch 1 as a special case because 1 ** n = 1 for all n
# and thus 1 ** n will never be greater than N causing an infinite loop
if k == 1: # If the power is one
return N == 1 # Then N is a power only if it is 1
for i in counting_numbers():
x = k ** i
if x == N :
return True
elif x > N:
return False
As you can see, you write what looks like a normal function and then use yield
wherever you want to give a value to the for loop. The generator you are writing will yield control over to the loop whenever it hits a yield statement which is why this generator doesn't cause the program to seize up in an infinite loop. You can read more about generators in their original PEP 255 or in various online tutorials. Just know that they will stop upon hitting the end of their block like a function would or a return
statement. (Sidenote: don't try using return x
in a generator, this is related to sending a StopIteration
and doesn't make the generator return a value like you might expect.)
In this case, we actually don't have to write counting_numbers
because itertools
already has this builtin as itertools.count
but because we want to start from 1 instead of 0 we will have to call count(1)
instead of count()
which would start from 0. We can now rewrite the above solution to
from itertools import count
def check_power(N, k):
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# This special case is to avoid an infinite loop
if k == 1:
return N == 1
for i in count(1):
x = k ** i
if x == N :
return True
elif x > N:
return False
This answer will focus on cleaning up the algorithm you used although, as other answers have shown, there are better algorithms for this problem. I will also answer how to loop over the infinite list of natural numbers with a generator. (Although I will refer to these as the counting numbers to clarify that I am not including 0.)
"Flat is better than nested"
An if statement that is checking a precondition for a function should avoid else
because the else makes the entire function more deeply nested and adds little to the understandability when it is clear that the if statement is there to check if the provided arguments are valid.
Misc
I recommend returning True
or False
instead of printing so that you can reuse this function in later problems. As a slight benefit, returning a value also removes the need for break
.
I also recommend using from __future__ import print_function
so that you can be forwards compatible with Python3. Note that you will have to use parentheses with print
and the new version below doesn't use print so this was left out of the code below.
Generators
Answering your question about how to loop over all the counting numbers, you could use a while loop or you could use generators. To show what your code might look like with a generator, see the following.
def counting_numbers():
i = 1
while True:
yield i
i += 1
def check_power(N, k):
# Note that you could include 0 if you're careful about it.
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# We need to catch 1 as a special case because 1 ** n = 1 for all n
# and thus 1 ** n will never be greater than N causing an infinite loop
if k == 1: # If the power is one
return N == 1 # Then N is a power only if it is 1
for i in counting_numbers():
x = k ** i
if x == N :
return True
elif x > N:
return False
As you can see, you write what looks like a normal function and then use yield
wherever you want to give a value to the for loop. The generator you are writing will yield control over to the loop whenever it hits a yield statement which is why this generator doesn't cause the program to seize up in an infinite loop. You can read more about generators in their original PEP 255 or in various online tutorials. Just know that they will stop upon hitting the end of their block like a function would or a return
statement. (Sidenote: don't try using return x
in a generator, this is related to sending a StopIteration
and doesn't make the generator return a value like you might expect.)
In this case, we actually don't have to write counting_numbers
because itertools
already has this builtin as itertools.count
but because we want to start from 1 instead of 0 we will have to call count(1)
instead of count()
which would start from 0. We can now rewrite the above solution to
from itertools import count
def check_power(N, k):
if N <= 0 or k <= 0:
raise ValueError("N and k should be greater than 0")
# This special case is to avoid an infinite loop
if k == 1:
return N == 1
for i in count(1):
x = k ** i
if x == N :
return True
elif x > N:
return False
answered Jan 5 at 4:25
dbramucci
311
311
add a comment |Â
add a comment |Â
up vote
0
down vote
This can be done without looping. The idea is to rearrange
$$N=k^c$$
to
$$c = log_k N = fraclog Nlog k.$$
If the exponent is an integer, then it is a perfect power. In the below code, some extra work is done to avoid floating-point rounding errors.
import math
def check_Power(N,k):
# input validation
if N < 0:
raise Exception('N must be non-negative')
if k < 0:
raise Exception('k must be non-negative')
# 1 to any power can only equal 1
if k == 1:
return N == 1
# Only raising 0 to a non-zero power results in zero
if N == 0 or k == 0:
return k == N
# Use math.floor to make the exponent an integer
# that is within 1 of the actual answer
exponent = math.floor(math.log(N)/math.log(k))
# Test whether the integer exponent solves
# the problem and adjust the exponent as needed
testN = k**exponent
if testN < N:
exponent += 1
elif testN > N:
exponent -= 1
else:
return True # testN == N
return k**exponent == N # check adjusted exponent
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
add a comment |Â
up vote
0
down vote
This can be done without looping. The idea is to rearrange
$$N=k^c$$
to
$$c = log_k N = fraclog Nlog k.$$
If the exponent is an integer, then it is a perfect power. In the below code, some extra work is done to avoid floating-point rounding errors.
import math
def check_Power(N,k):
# input validation
if N < 0:
raise Exception('N must be non-negative')
if k < 0:
raise Exception('k must be non-negative')
# 1 to any power can only equal 1
if k == 1:
return N == 1
# Only raising 0 to a non-zero power results in zero
if N == 0 or k == 0:
return k == N
# Use math.floor to make the exponent an integer
# that is within 1 of the actual answer
exponent = math.floor(math.log(N)/math.log(k))
# Test whether the integer exponent solves
# the problem and adjust the exponent as needed
testN = k**exponent
if testN < N:
exponent += 1
elif testN > N:
exponent -= 1
else:
return True # testN == N
return k**exponent == N # check adjusted exponent
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
add a comment |Â
up vote
0
down vote
up vote
0
down vote
This can be done without looping. The idea is to rearrange
$$N=k^c$$
to
$$c = log_k N = fraclog Nlog k.$$
If the exponent is an integer, then it is a perfect power. In the below code, some extra work is done to avoid floating-point rounding errors.
import math
def check_Power(N,k):
# input validation
if N < 0:
raise Exception('N must be non-negative')
if k < 0:
raise Exception('k must be non-negative')
# 1 to any power can only equal 1
if k == 1:
return N == 1
# Only raising 0 to a non-zero power results in zero
if N == 0 or k == 0:
return k == N
# Use math.floor to make the exponent an integer
# that is within 1 of the actual answer
exponent = math.floor(math.log(N)/math.log(k))
# Test whether the integer exponent solves
# the problem and adjust the exponent as needed
testN = k**exponent
if testN < N:
exponent += 1
elif testN > N:
exponent -= 1
else:
return True # testN == N
return k**exponent == N # check adjusted exponent
This can be done without looping. The idea is to rearrange
$$N=k^c$$
to
$$c = log_k N = fraclog Nlog k.$$
If the exponent is an integer, then it is a perfect power. In the below code, some extra work is done to avoid floating-point rounding errors.
import math
def check_Power(N,k):
# input validation
if N < 0:
raise Exception('N must be non-negative')
if k < 0:
raise Exception('k must be non-negative')
# 1 to any power can only equal 1
if k == 1:
return N == 1
# Only raising 0 to a non-zero power results in zero
if N == 0 or k == 0:
return k == N
# Use math.floor to make the exponent an integer
# that is within 1 of the actual answer
exponent = math.floor(math.log(N)/math.log(k))
# Test whether the integer exponent solves
# the problem and adjust the exponent as needed
testN = k**exponent
if testN < N:
exponent += 1
elif testN > N:
exponent -= 1
else:
return True # testN == N
return k**exponent == N # check adjusted exponent
answered Jan 5 at 3:32
Mark H
362110
362110
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
add a comment |Â
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
Isn't that essentially what codereview.stackexchange.com/a/184267/35991 suggests?
â Martin R
Jan 5 at 6:24
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
@MartinR Now that I look at it more carefully, yes.
â Mark H
Jan 5 at 7:07
add a comment |Â
up vote
0
down vote
I'm going to assume you mean integers since that's what your test data suggests. I'm also assuming the powers are non-negative integers so as not to involve roots (a).
In that case, there's no need to do all those power calculations, you just need to realise that, if n
is a power of k
, then continuously multiplying an accumulator (initially k
) by k
will either:
- reach
n
exactly (if it's a power). - exceed
n
(if it's not a power).
never satisfy either of those conditions because the accumulator never gets any closer ton
(see below code for those conditions).
In any case, the code you have only checks if n
is a power of k
with an exponent less than or equal to twenty, it won't return true for k = 2, n = 2**31
for example.
The code to do it a a less limited way is a stunningly simple:
def isPower(n, k):
# Special cases.
if k == 0: return n == 0 # 0^not-0 always 0, 0^0 undefined
if k == 1: return n == 1 # 1^n always 1
if k == -1: return abs(n) == 1 # -1^n alternates +/-1
# abs(k) is now >= 2 so it will always increase in magnitude.
acc = k
while abs(acc) < abs(n):
acc = acc * k
return acc == n
(a) If you decide to use floating point values, it gets a little more complicated. You then have to cater for more possibilities:
- if the power is allowed to be fractional, you'll have to cater for roots as well as powers;
- where
k
is be between -1 and 1, it will always approach zero rather than getting larger, so you'll need to adapt for that; - the adaptation for that must also take into account whether
n
is in that range or whether its absolute value is greater than or equal to one;
There's may well be other issues that haven't sprung immediately to mind, I won't think too much about them as, in the absence of further information, they're probably unnecessary.
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
For which negative input? YourisPower(-8, -2)
returns False.
â Martin R
Jan 5 at 7:03
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
YourisPower(1, -1)
returns False.
â Martin R
Jan 5 at 7:55
 |Â
show 2 more comments
up vote
0
down vote
I'm going to assume you mean integers since that's what your test data suggests. I'm also assuming the powers are non-negative integers so as not to involve roots (a).
In that case, there's no need to do all those power calculations, you just need to realise that, if n
is a power of k
, then continuously multiplying an accumulator (initially k
) by k
will either:
- reach
n
exactly (if it's a power). - exceed
n
(if it's not a power).
never satisfy either of those conditions because the accumulator never gets any closer ton
(see below code for those conditions).
In any case, the code you have only checks if n
is a power of k
with an exponent less than or equal to twenty, it won't return true for k = 2, n = 2**31
for example.
The code to do it a a less limited way is a stunningly simple:
def isPower(n, k):
# Special cases.
if k == 0: return n == 0 # 0^not-0 always 0, 0^0 undefined
if k == 1: return n == 1 # 1^n always 1
if k == -1: return abs(n) == 1 # -1^n alternates +/-1
# abs(k) is now >= 2 so it will always increase in magnitude.
acc = k
while abs(acc) < abs(n):
acc = acc * k
return acc == n
(a) If you decide to use floating point values, it gets a little more complicated. You then have to cater for more possibilities:
- if the power is allowed to be fractional, you'll have to cater for roots as well as powers;
- where
k
is be between -1 and 1, it will always approach zero rather than getting larger, so you'll need to adapt for that; - the adaptation for that must also take into account whether
n
is in that range or whether its absolute value is greater than or equal to one;
There's may well be other issues that haven't sprung immediately to mind, I won't think too much about them as, in the absence of further information, they're probably unnecessary.
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
For which negative input? YourisPower(-8, -2)
returns False.
â Martin R
Jan 5 at 7:03
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
YourisPower(1, -1)
returns False.
â Martin R
Jan 5 at 7:55
 |Â
show 2 more comments
up vote
0
down vote
up vote
0
down vote
I'm going to assume you mean integers since that's what your test data suggests. I'm also assuming the powers are non-negative integers so as not to involve roots (a).
In that case, there's no need to do all those power calculations, you just need to realise that, if n
is a power of k
, then continuously multiplying an accumulator (initially k
) by k
will either:
- reach
n
exactly (if it's a power). - exceed
n
(if it's not a power).
never satisfy either of those conditions because the accumulator never gets any closer ton
(see below code for those conditions).
In any case, the code you have only checks if n
is a power of k
with an exponent less than or equal to twenty, it won't return true for k = 2, n = 2**31
for example.
The code to do it a a less limited way is a stunningly simple:
def isPower(n, k):
# Special cases.
if k == 0: return n == 0 # 0^not-0 always 0, 0^0 undefined
if k == 1: return n == 1 # 1^n always 1
if k == -1: return abs(n) == 1 # -1^n alternates +/-1
# abs(k) is now >= 2 so it will always increase in magnitude.
acc = k
while abs(acc) < abs(n):
acc = acc * k
return acc == n
(a) If you decide to use floating point values, it gets a little more complicated. You then have to cater for more possibilities:
- if the power is allowed to be fractional, you'll have to cater for roots as well as powers;
- where
k
is be between -1 and 1, it will always approach zero rather than getting larger, so you'll need to adapt for that; - the adaptation for that must also take into account whether
n
is in that range or whether its absolute value is greater than or equal to one;
There's may well be other issues that haven't sprung immediately to mind, I won't think too much about them as, in the absence of further information, they're probably unnecessary.
I'm going to assume you mean integers since that's what your test data suggests. I'm also assuming the powers are non-negative integers so as not to involve roots (a).
In that case, there's no need to do all those power calculations, you just need to realise that, if n
is a power of k
, then continuously multiplying an accumulator (initially k
) by k
will either:
- reach
n
exactly (if it's a power). - exceed
n
(if it's not a power).
never satisfy either of those conditions because the accumulator never gets any closer ton
(see below code for those conditions).
In any case, the code you have only checks if n
is a power of k
with an exponent less than or equal to twenty, it won't return true for k = 2, n = 2**31
for example.
The code to do it a a less limited way is a stunningly simple:
def isPower(n, k):
# Special cases.
if k == 0: return n == 0 # 0^not-0 always 0, 0^0 undefined
if k == 1: return n == 1 # 1^n always 1
if k == -1: return abs(n) == 1 # -1^n alternates +/-1
# abs(k) is now >= 2 so it will always increase in magnitude.
acc = k
while abs(acc) < abs(n):
acc = acc * k
return acc == n
(a) If you decide to use floating point values, it gets a little more complicated. You then have to cater for more possibilities:
- if the power is allowed to be fractional, you'll have to cater for roots as well as powers;
- where
k
is be between -1 and 1, it will always approach zero rather than getting larger, so you'll need to adapt for that; - the adaptation for that must also take into account whether
n
is in that range or whether its absolute value is greater than or equal to one;
There's may well be other issues that haven't sprung immediately to mind, I won't think too much about them as, in the absence of further information, they're probably unnecessary.
edited Jan 5 at 8:37
answered Jan 5 at 5:47
user7649
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
For which negative input? YourisPower(-8, -2)
returns False.
â Martin R
Jan 5 at 7:03
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
YourisPower(1, -1)
returns False.
â Martin R
Jan 5 at 7:55
 |Â
show 2 more comments
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
For which negative input? YourisPower(-8, -2)
returns False.
â Martin R
Jan 5 at 7:03
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
YourisPower(1, -1)
returns False.
â Martin R
Jan 5 at 7:55
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
Isn't that essentially the solution suggested in this answer codereview.stackexchange.com/a/184266/35991 ?
â Martin R
Jan 5 at 6:11
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
The fact that the five lines of calculation loop is pretty much the same does not, I believe make the answer as a whole identical. There is no reason to limit the input variables to positive integers, my answer allows for either sign. It also details what would be needed to make it work for non-integers as well.
â user7649
Jan 5 at 6:39
For which negative input? Your
isPower(-8, -2)
returns False.â Martin R
Jan 5 at 7:03
For which negative input? Your
isPower(-8, -2)
returns False.â Martin R
Jan 5 at 7:03
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
@MartinR, good catch, I believe I've fixed that now, it was a slight bug in the terminating condition for the loop.
â user7649
Jan 5 at 7:10
Your
isPower(1, -1)
returns False.â Martin R
Jan 5 at 7:55
Your
isPower(1, -1)
returns False.â Martin R
Jan 5 at 7:55
 |Â
show 2 more comments
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184260%2fcheck-if-a-given-number-n-is-a-power-of-k%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
For
N
to be a multiple ofk
it must be not less thank
and must give an integer result when divided byk
. If it is a power ofk
then the result of division must be either1
of a multiple ofk
. So, you can just iterate dividingN
byk
as long asN
is greater or equalk
. Then, if it became1
, the initial value was a power ofk
, otherwise it wasn't.â CiaPan
Jan 4 at 10:18
One more note: test for
k
equal1
â no number (except1
itself) can be a power of1
...â CiaPan
Jan 4 at 10:20
Duplicate of codereview.stackexchange.com/questions/160924/⦠?
â dberm22
Jan 5 at 13:57