简体   繁体   English

如何检查给定数字是否是 2 的幂?

[英]How to check if a given number is a power of two?

The code below isn't working right for some inputs.下面的代码不适用于某些输入。

a, i = set(), 1
while i <= 10000:
    a.add(i)
    i <<= 1

N = int(input())
if N in a:
    print("True")
else:
    print("False")

My initial idea was to check for each input if it's a power of 2 by starting from 1 and multiplying by 2 until exceeding the input number, comparing at each step.我最初的想法是检查每个输入是否是 2 的幂,方法是从 1 开始并乘以 2 直到超过输入数,在每一步进行比较。 Instead, I store all the powers of 2 in a set beforehand, in order to check a given input in O(1) .相反,我预先将 2 的所有幂存储在一个set中,以便检查O(1)中的给定输入。 How can this be improved?如何改进?

Bit Manipulations位操作

One approach would be to use bit manipulations :一种方法是使用位操作

(n & (n-1) == 0) and n != 0

Explanation: every power of 2 has exactly 1 bit set to 1 (the bit in that number's log base-2 index).说明:每个 2 的幂都有 1 位设置为 1(该数字的日志 base-2 索引中的位)。 So when subtracting 1 from it, that bit flips to 0 and all preceding bits flip to 1. That makes these 2 numbers the inverse of each other so when AND-ing them, we will get 0 as the result.因此,当从中减去 1 时,该位翻转为 0,并且所有前面的位翻转为 1。这使得这两个数字彼此相反,因此当对它们进行与运算时,我们将得到 0 作为结果。

For example:例如:

                    n = 8

decimal |   8 = 2**3   |  8 - 1 = 7   |   8 & 7 = 0
        |          ^   |              |
binary  |   1 0 0 0    |   0 1 1 1    |    1 0 0 0
        |   ^          |              |  & 0 1 1 1
index   |   3 2 1 0    |              |    -------
                                           0 0 0 0
-----------------------------------------------------
                    n = 5

decimal | 5 = 2**2 + 1 |  5 - 1 = 4   |   5 & 4 = 4
        |              |              |
binary  |    1 0 1     |    1 0 0     |    1 0 1
        |              |              |  & 1 0 0
index   |    2 1 0     |              |    ------
                                           1 0 0

So, in conclusion, whenever we subtract one from a number, AND the result with the number itself, and that becomes 0 - that number is a power of 2!因此,总而言之,每当我们从一个数字中减去一个,并将结果与​​数字本身相乘,结果就变成了 0 - 这个数字是 2 的幂!

Of course, AND-ing anything with 0 will give 0, so we add the check for n != 0 .当然,任何与0的 AND 运算都会得到 0,因此我们添加了对n != 0的检查。


math functions math函数

You could always use math functions, but notice that using them without care could cause incorrect results :您总是可以使用数学函数,但请注意,不小心使用它们可能会导致错误的结果

Worth noting that for any n <= 0 , both functions will throw a ValueError as it is mathematically undefined (and therefore shouldn't present a logical problem).值得注意的是,对于任何n <= 0 ,这两个函数都会抛出一个ValueError ,因为它在数学上是未定义的(因此不应该出现逻辑问题)。

As noted above, for some numbers these functions are not accurate and actually give FALSE RESULTS :如上所述,对于某些数字,这些函数并不准确,实际上会给出FALSE RESULTS

  • math.log(2**29, 2).is_integer() will give False math.log(2**29, 2).is_integer()将给出False
  • math.log2(2**49-1).is_integer() will give True math.log2(2**49-1).is_integer()将给出True
  • math.frexp(2**53+1)[0] == 0.5 will give True !! math.frexp(2**53+1)[0] == 0.5将给出True !!

This is because math functions use floats, and those have an inherent accuracy problem .这是因为math函数使用浮点数,而这些函数存在固有的准确性问题


(Expanded) Timing (扩展)时序

Some time has passed since this question was asked and some new answers came up with the years.自从提出这个问题以来已经过去了一段时间,这些年来提出了一些新的答案。 I decided to expand the timing to include all of them.我决定扩大时间以包括所有这些。

According to the math docs , the log with a given base, actually calculates log(x)/log(base) which is obviously slow.根据数学文档,具有给定基数的log实际上计算log(x)/log(base)显然很慢。 log2 is said to be more accurate, and probably more efficient.据说log2更准确,并且可能更有效。 Bit manipulations are simple operations, not calling any functions.位操作是简单的操作,不调用任何函数。

So the results are:所以结果是:

Ev : 0.28 sec Ev : 0.28 秒

log with base=2 : 0.26 secbase=2 log :0.26 秒

count_1 : 0.21 sec count_1 :0.21 秒

check_1 : 0.2 sec check_1 :0.2 秒

frexp : 0.19 sec frexp :0.19 秒

log2 : 0.1 sec log2 :0.1 秒

bit ops: 0.08 sec位操作:0.08 秒

The code I used for these measures can be recreated in this REPL (forked from this one ).我用于这些措施的代码可以在这个 REPL中重新创建(从这个分支)。

Refer to the excellent and detailed answer to "How to check if a number is a power of 2" — for C#.请参阅“如何检查数字是否为 2 的幂”的出色而详细的答案- 对于 C#。 The equivalent Python implementation, also using the "bitwise and" operator & , is this:等效的 Python 实现,也使用“按位与”运算符& ,是这样的:

def is_power_of_two(n):
    return (n != 0) and (n & (n-1) == 0)

As Python has arbitrary-precision integers , this works for any integer n as long as it fits into memory.由于Python 具有任意精度的整数,因此它适用于任何整数n ,只要它适合内存即可。

To summarize briefly the answer cited above: The first term, before the logical and operator, simply checks if n isn't 0 — and hence not a power of 2. The second term checks if it's a power of 2 by making sure that all bits after that bitwise & operation are 0. The bitwise operation is designed to be only True for powers of 2 — with one exception: if n (and thus all of its bits) were 0 to begin with.简要总结上面引用的答案:第一项,在逻辑and运算符之前,只是检查n是否不是 0 - 因此不是2 的幂。第二项通过确保所有按位&运算之后的位为 0。按位运算设计为仅对 2 的幂为True ——除了一个例外:如果n (以及它的所有位)一开始就为 0。

To add to this: As the logical and "short-circuits" the evaluation of the two terms, it would be more efficient to reverse their order if, in a particular use case, it is less likely that a given n be 0 than it being a power of 2.补充一点:由于对这两个术语的评估是逻辑and “短路” ,如果在特定用例中,给定的n不太可能是 0,那么颠倒它们的顺序会更有效。是 2 的幂。

In binary representation, a power of 2 is a 1 (one) followed by zeros.在二进制表示中,2 的幂是 1(一)后跟零。 So if the binary representation of the number has a single 1, then it's a power of 2. No need here to check num != 0 :因此,如果数字的二进制表示只有一个 1,那么它就是 2 的幂。这里不需要检查num != 0

print(1 == bin(num).count("1")) 

Note: this should be a comment on Tomerikoo's answer (currently the most upvoted) but unfortunately Stack Overflow won't let me comment due to reputation points.注意:这应该是对 Tomerikoo 答案的评论(目前是最受好评的),但不幸的是,由于声誉点,Stack Overflow 不允许我发表评论。

Tomerikoo's answer is very well explained and thought-out. Tomerikoo 的回答得到了很好的解释和深思熟虑。 While it covers most applications, but I believe needs a slight modification to make it more robust against a trivial case.虽然它涵盖了大多数应用程序,但我认为需要稍作修改以使其对微不足道的情况更加健壮。 Their answer is:他们的回答是:

(n & (n-1) == 0) and n != 0

The second half checks if the input is an actual 0 which would invalidate the bitwise-and logic.后半部分检查输入是否为实际的 0,这将使按位与逻辑无效。 There is another one trivial case when this could happen: input is 1 and the bitwise-and takes place with 0 again, just on the second term.还有另一种可能发生这种情况的微不足道的情况:输入为 1 并且按位与 0 再次发生,就在第二项。 Strictly speaking, 2^0=1 of course but I doubt that it's useful for most applications.严格来说,当然是2^0=1 ,但我怀疑它对大多数应用程序是否有用。 A trivial modification to account for that would be:一个微不足道的修改可以解决这个问题:

(n & (n-1) == 0) and (n != 0 and n-1 != 0)

The bin builtin returns a string "0b1[01]?"内置bin返回一个字符串"0b1[01]?" (regex notation) for every strictly positive integer (if system memory suffices, that is), so that we can write the Boolean expression (正则表达式)对于每个严格的正整数(如果系统内存足够的话),这样我们就可以编写布尔表达式

'1' not in bin(abs(n))[3:]

that yields True for n that equals 0 , 1 and 2**k .对于等于012**kn产生True

1 is 2**0 so it is unquestionably a power of two, but 0 is not, unless you take into account the limit of x=2**k for k → -∞ . 12**0所以它毫无疑问是 2 的幂,但0不是,除非你考虑到k → -∞x=2**k的限制。 Under the second assumption we can write simply在第二个假设下,我们可以简单地写

check0 = lambda n: '1' not in bin(abs(n))[3:]

and under the first one (excluding 0 )并在第一个下(不包括0

check1 = lambda n: '1' not in bin(abs(n))[3:] and n != 0

Of course the solution here proposed is just one of the many possible ones that当然,这里提出的解决方案只是众多可能的解决方案之一
you can use to check if a number is a power of two... and for sure not the most你可以用它来检查一个数字是否是二的幂......并且肯定不是最
efficient one but I'm posting it in the sake of completeness :-)高效的,但为了完整起见,我将其发布:-)

The following code checks whether n is a power of 2 or not:以下代码检查 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")

Many beginners won't know how code like (n != 0) and (n & (n-1) == 0) works.许多初学者不知道(n != 0) and (n & (n-1) == 0)这样的代码是如何工作的。 But if we want to check whether a number is a power of 2 or not, we can convert the number to binary format and see it pretty clearly.但是如果我们想检查一个数字是否是 2 的幂,我们可以将这个数字转换为二进制格式并且看得很清楚。

For Example:例如:


      ^ (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)

If you look at the binary values of all powers of 2, you can see that there is only one bit True .如果您查看 2 的所有幂的二进制值,您会发现只有一位True That's the logic in this program.这就是这个程序的逻辑。

So If we count the number of 1 bit's in a binary number and if it is equal to 1, then the given number is power of 2, otherwise it is not.因此,如果我们计算二进制数中 1 位的数量,如果它等于 1,则给定数是 2 的幂,否则不是。

n = int(input())
if '1' in list(bin(n))[3:]: #also can use if '1' in bin(n)[3:]  OR can also use format(n, 'b')[1:]
    print("False")
else:
    print("True")

For every number which is power of 2 say(N = 2^n), where n = +integer bin(N)=bin(2^(+int)) will have string of form: 0b10000000 ei 0b1.....zero only if not 0, N is not power of 2.对于每个 2 的幂的数来说(N = 2^n),其中 n = +integer bin(N)=bin(2^(+int))将具有以下form: 0b10000000 ei 0b1.....仅当不是 0 时才为零,N 不是 2 的幂。

Also, format(n, 'b') returns bin(n)[2:] so can be used此外, format(n, 'b')返回bin(n)[2:]所以可以使用

  • Source资源

    >>> format(14, '#b'), format(14, 'b') ('0b1110', '1110') >>> f'{14:#b}', f'{14:b}' ('0b1110', '1110')

Use *2 instead of bit shifts.使用 *2 而不是位移。 Multiplication or addition are much more readable.乘法或加法更具可读性。

Most of the above answers use bin() of format(int(input()), "b")上面的大多数答案都使用格式的bin() format(int(input()), "b")

The below code also works: Ev(x) returns True if x is power of 2下面的代码也有效:如果x是 2 的幂,则Ev(x)返回 True

# Ev(x) ~ ispoweroftwo(x)
def Ev(x):
    if x==2:        return True
    elif x%2:       return False
    return Ev(x//2)

The above code is based on generating bin()以上代码基于生成bin()

#This function returns binary of integers
def binary(x):
        a = ""
        while x!= 0:
                a += str(x%2)
                x = x//2
        return a[::-1]

I = int(input())
print(format(I, "b")) # To cross-check if equal of not
print(binary(I))

I have tried to add my answer because I found what we are doing using bin(x)[3:] or format(x, "b") is almost like asking the boolean answer of whether or not a given number x is divisible by two.....and we keep asking the same我试图添加我的答案,因为我发现我们使用bin(x)[3:]format(x, "b")所做的几乎就像询问给定数字x是否可被整除的布尔答案两个......我们一直在问同样的问题

I have written a python function that will check the power of any number:我编写了一个 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()))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM