下面的代码不适用于某些输入。
a, i = set(), 1
while i <= 10000:
a.add(i)
i <<= 1
N = int(input())
if N in a:
print("True")
else:
print("False")
我的想法是,不是先检查每个输入是否为2的幂,而是从1开始乘以2直到超过输入数,然后在每一步进行比较,而是将所有2的幂存储在一组中为了检查O(1)中的给定输入。如何改善呢?
答案 0 :(得分:3)
您是否故意避开图书馆?
如果没有,您可以使用math
来发挥自己的力量(明白吗?力量……没关系):
import math
math.log(n, 2).is_integer()
EDIT1 :或交替使用:
math.log2(n).is_integer()
值得一提的是,对于任何n <= 0
来说,它们都会抛出ValueError
,因为它在数学上是未定义的(因此不应出现逻辑问题)。
EDIT2 :但是最好的方法是使用位操作:
(n & (n-1) == 0) and n != 0
EDIT1:计时
根据@FilipHaglund的评论,我返回到math docs,以尝试收集有关效率的信息。我发现具有给定基数的log
方法实际上计算出的log(x)/log(base)
显然要慢一些。
比我看到的还有另一种方法log2
-仅需要一个数字,显然可以计算其以2为底的对数,听起来应该更快。
最后,我想看看它们与二进制方法的比较。结果是:
将
log
与参数base=2
一起使用:2.672359s使用
log2
:2.114203秒使用二进制方法:1.352385s
下面是我用于这些措施的代码。我基本上要做的是检查1到1M之间的所有数字,每种方法是否都是2的幂,重复10次并求平均值。当然,这不是科学的,但是可以提供一个想法...
EDIT2 :还应该注意,对于很大的数字(例如2**100
),第一个log
并不准确,实际上给出了假阴性。
import time
import math
funcs = {"log with base 2": lambda i: math.log(i, 2).is_integer(),
"log2": lambda i: math.log2(i).is_integer(),
"binary": lambda i: (i & (i-1) == 0) and i != 0}
times = {k: [] for k in funcs}
for _ in range(10):
for typ in funcs:
func = funcs[typ]
start = time.time()
for i in range(1, 1000000):
func(i)
times[typ].append(time.time()-start)
for typ in times:
avg = sum(times[typ])/len(times[typ])
print("{}: {:f}".format(typ, avg))
希望您发现我的小研究有用:)
答案 1 :(得分:3)
有关C#,请参考出色而详尽的answer to "How to check if a number is a power of 2"。同样也使用"bitwise and" operator &
的Python实现是这样的:
def is_power_of_two(n):
return (n != 0) and (n & (n-1) == 0)
与Python has arbitrary-precision integers一样,它适用于任何整数n
,只要它适合内存即可。
简单总结一下上面引用的答案:在逻辑and
运算符之前的第一项,只需检查n
是否不为0 —因此不是的2。第二项通过确保按位&
之后的 all 位为0,检查它是否为2的幂。按位运算被设计为仅{{1} }的2的幂-一个例外:如果True
(及其所有位)都从0开始。
要补充一点:作为logical and
"short-circuits"这两个词的评估,如果在特定用例中可能性 ,颠倒它们的顺序将更为有效。给定的n
为0而不是2的幂。
答案 2 :(得分:2)
注意:这应该是对 Tomerikoo 答案的评论(目前投票最多),但不幸的是 Stack Overflow 由于声誉点而不允许我发表评论。
Tomerikoo 的回答很好解释和深思熟虑。虽然它涵盖了大多数应用程序,但我认为需要稍作修改以使其在处理琐碎情况时更加健壮。他们的回答是:
(n & (n-1) == 0) and n != 0
后半部分检查输入是否为实际的 0,这会使按位与逻辑无效。还有另一种可能发生这种情况的微不足道的情况:输入为 1 并且按位并再次与 0 一起发生,就在第二项上。严格来说,2^0=1
当然可以,但我怀疑它对大多数应用程序是否有用。一个微不足道的修改是:
(n & (n-1) == 0) and (n != 0 and n-1 != 0)
答案 3 :(得分:1)
使用* 2代替位移。位移的大小受int大小的限制,但乘法没有限制。乘法或加法也更具可读性。
答案 4 :(得分:1)
以下代码检查 n 是否为 2 的幂:
def power_of_two(n):
count = 0
st = str(bin(n))
st = st[2:]
for i in range(0,len(st)):
if(st[i] == '1'):
count += 1
if(count == 1):
print("True")
else:
print("False")
许多初学者不会知道像 (n != 0) and (n & (n-1) == 0)
这样的代码是如何工作的。
但是如果我们想检查一个数是否是 2 的幂,我们可以把这个数转换成二进制格式,看的很清楚。
例如:
^ (to the power of)
2^0 = 1 (Bin Value : 0000 0001)
2^1 = 2 (Bin Value : 0000 0010)
2^2 = 4 (Bin Value : 0000 0100)
2^3 = 8 (Bin Value : 0000 1000)
2^4 = 16 (Bin Value : 0001 0000)
2^5 = 32 (Bin Value : 0010 0000)
2^6 = 64 (Bin Value : 0100 0000)
2^7 = 128 (Bin Value : 1000 0000)
如果您查看 2 的所有幂的二进制值,您会发现只有一位 True
。这就是这个程序的逻辑。
所以如果我们计算一个二进制数中 1 位的个数,如果它等于 1,那么给定的数是 2 的幂,否则不是。
答案 5 :(得分:0)
bin
内置函数为每个严格的正整数返回一个字符串"0b1[01]?"
(正则表达式)(如果系统内存足够的话),因此我们可以编写布尔表达式
'1' not in bin(abs(n))[3:]
得出True
等于n
,0
和1
的{{1}}的{p}。
2**k
是1
,因此毫无疑问是2的幂,但是2**0
不是2,除非您考虑{{1}的0
的限制}。在第二种假设下,我们可以简单地写
x=2**k
并且在第一个(不包括k → -∞
)
check0 = lambda n: '1' not in bin(abs(n))[3:]
当然,这里提出的解决方案只是众多可能的解决方案之一
您可以用来检查数字是否是2的幂...并且肯定不是最大的
高效的一个,但为了完整起见,我将其发布:-)
答案 6 :(得分:-1)
我写了一个python函数,可以检查任何数字的幂:
import math
def checkPowTwo(num):
x = int(input("The power of the number to be calculated is: "))
output = math.log(num, x)
residue = output - int(output)
if residue == 0:
print (num, " is a power of the number desired.")
else:
print (num, " is not a power of the number desired.")
y = checkPowTwo(int(input()))