在Python中检查给定数字是否为2的幂

时间:2019-07-14 08:44:11

标签: python

下面的代码不适用于某些输入。

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)中的给定输入。如何改善呢?

7 个答案:

答案 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等于n01的{​​{1}}的{​​p}。

2**k1,因此毫无疑问是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()))