如何判断一个数是否是2的幂

发布于 2024-07-14 04:45:24 字数 1104 浏览 5 评论 0原文

今天,我需要一个简单的算法来检查一个数字是否是 2 的幂。

该算法需要是:

  1. 简单
  2. 正确任何 ulong 值。

我想出了这个简单的算法:

private bool IsPowerOfTwo(ulong number)
{
    if (number == 0)
        return false;

    for (ulong power = 1; power > 0; power = power << 1)
    {
        // This for loop used shifting for powers of 2, meaning
        // that the value will become 0 after the last shift
        // (from binary 1000...0000 to 0000...0000) then, the 'for'
        // loop will break out.

        if (power == number)
            return true;
        if (power > number)
            return false;
    }
    return false;
}

但后来我想:检查 log2 x 是否恰好是一个整数怎么样? 当我检查 2^63+1 时,由于四舍五入,Math.Log() 恰好返回 63。 所以我检查了 2 的 63 次方是否等于原始数字,确实如此,因为计算是在 double 中完成的,而不是精确数字。

private bool IsPowerOfTwo_2(ulong number)
{
    double log = Math.Log(number, 2);
    double pow = Math.Pow(2, Math.Round(log));
    return pow == number;
}

对于给定的错误值,这返回了 true9223372036854775809

有更好的算法吗?

Today I needed a simple algorithm for checking if a number is a power of 2.

The algorithm needs to be:

  1. Simple
  2. Correct for any ulong value.

I came up with this simple algorithm:

private bool IsPowerOfTwo(ulong number)
{
    if (number == 0)
        return false;

    for (ulong power = 1; power > 0; power = power << 1)
    {
        // This for loop used shifting for powers of 2, meaning
        // that the value will become 0 after the last shift
        // (from binary 1000...0000 to 0000...0000) then, the 'for'
        // loop will break out.

        if (power == number)
            return true;
        if (power > number)
            return false;
    }
    return false;
}

But then I thought: How about checking if log2 x is an exactly a round number? When I checked for 2^63+1, Math.Log() returned exactly 63 because of rounding. So I checked if 2 to the power 63 is equal to the original number and it is, because the calculation is done in doubles and not in exact numbers.

private bool IsPowerOfTwo_2(ulong number)
{
    double log = Math.Log(number, 2);
    double pow = Math.Pow(2, Math.Round(log));
    return pow == number;
}

This returned true for the given wrong value: 9223372036854775809.

Is there a better algorithm?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

原来分手还会想你 2024-07-21 04:45:24

对于这个问题有一个简单的技巧:

bool IsPowerOfTwo(ulong x)
{
    return (x & (x - 1)) == 0;
}

注意,此函数将为 0 报告 true,这不是 2 的幂。 如果您想排除它,请执行以下操作:

bool IsPowerOfTwo(ulong x)
{
    return (x != 0) && ((x & (x - 1)) == 0);
}

解释

首先也是最重要的是按位二进制 & MSDN 定义中的运算符:

二进制和 运算符是为整数类型和布尔值预定义的。 为了
整数类型,& 计算其操作数的逻辑按位与。
对于布尔操作数,& 计算其操作数的逻辑与; 那
也就是说,当且仅当其两个操作数都为 true 时,结果才为 true。

现在让我们看一下这一切是如何进行的:

该函数返回布尔值(true / false)并接受一个 unsigned long 类型(在本例中为 x)的传入参数。 为了简单起见,让我们假设有人传递了值 4 并像这样调用该函数:

bool b = IsPowerOfTwo(4)

现在我们将每次出现的 x 替换为 4:

return (4 != 0) && ((4 & (4-1)) == 0);

我们已经知道 4 != 0 的值为 true,到目前为止一切顺利。 但是呢:

((4 & (4-1)) == 0)

这当然可以翻译成:

((4 & 3) == 0)

但是 4&3 到底是什么?

4 的二进制表示形式是 100,3 的二进制表示形式是 011(请记住 & 采用这些数字的二进制表示形式)。 所以我们有:

100 = 4
011 = 3

想象一下这些值像基本加法一样堆叠起来。 & 运算符表示如果两个值都等于 1,则结果为 1,否则结果为 0。因此 1 & 1 = 1,1 & 0 = 0, 0 & 0 = 0,以及0 & 1 = 0。 所以我们计算一下:

100
011
----
000

结果就是 0。所以我们回去看看 return 语句现在翻译成什么:

return (4 != 0) && ((4 & 3) == 0);

现在翻译成:

return true && (0 == 0);
return true && true;

我们都知道 true && true 就是 true,这表明在我们的示例中,4 是 2 的幂。

There's a simple trick for this problem:

bool IsPowerOfTwo(ulong x)
{
    return (x & (x - 1)) == 0;
}

Note, this function will report true for 0, which is not a power of 2. If you want to exclude that, here's how:

bool IsPowerOfTwo(ulong x)
{
    return (x != 0) && ((x & (x - 1)) == 0);
}

Explanation

First and foremost the bitwise binary & operator from MSDN definition:

Binary & operators are predefined for the integral types and bool. For
integral types, & computes the logical bitwise AND of its operands.
For bool operands, & computes the logical AND of its operands; that
is, the result is true if and only if both its operands are true.

Now let's take a look at how this all plays out:

The function returns boolean (true / false) and accepts one incoming parameter of type unsigned long (x, in this case). Let us for the sake of simplicity assume that someone has passed the value 4 and called the function like so:

bool b = IsPowerOfTwo(4)

Now we replace each occurrence of x with 4:

return (4 != 0) && ((4 & (4-1)) == 0);

Well we already know that 4 != 0 evals to true, so far so good. But what about:

((4 & (4-1)) == 0)

This translates to this of course:

((4 & 3) == 0)

But what exactly is 4&3?

The binary representation of 4 is 100 and the binary representation of 3 is 011 (remember the & takes the binary representation of these numbers). So we have:

100 = 4
011 = 3

Imagine these values being stacked up much like elementary addition. The & operator says that if both values are equal to 1 then the result is 1, otherwise it is 0. So 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, and 0 & 1 = 0. So we do the math:

100
011
----
000

The result is simply 0. So we go back and look at what our return statement now translates to:

return (4 != 0) && ((4 & 3) == 0);

Which translates now to:

return true && (0 == 0);
return true && true;

We all know that true && true is simply true, and this shows that for our example, 4 is a power of 2.

旧话新听 2024-07-21 04:45:24

一些记录和解释这种和其他一些琐碎黑客的网站是:

)他们的祖父,小亨利·沃伦 (Henry Warren, Jr.) 的书《黑客的乐趣》

作为Sean Anderson 的页面 解释了表达式 ((x & (x - 1)) == 0)错误地指出 0 是 2 的幂。他建议使用:

(!(x & (x - 1)) && x)

来纠正该问题。

Some sites that document and explain this and other bit twiddling hacks are:

And the grandaddy of them, the book "Hacker's Delight" by Henry Warren, Jr.:

As Sean Anderson's page explains, the expression ((x & (x - 1)) == 0) incorrectly indicates that 0 is a power of 2. He suggests to use:

(!(x & (x - 1)) && x)

to correct that problem.

浪推晚风 2024-07-21 04:45:24

返回(i & -i) == i

return (i & -i) == i

太阳哥哥 2024-07-21 04:45:24

以下对已接受答案的补充可能对某些人有用:

以二进制表示时,2 的幂总是看起来像 1 后跟 n 个零,其中 n 大于或等于 0。例如:

Decimal  Binary
1        1     (1 followed by 0 zero)
2        10    (1 followed by 1 zero)
4        100   (1 followed by 2 zeroes)
8        1000  (1 followed by 3 zeroes)
.        .
.        .
.        .

等等。

当我们从这些数字中减去 1 时,它们会变成 0 后跟 n 个,并且 n 与上面相同。 例如:

Decimal    Binary
1 - 1 = 0  0    (0 followed by 0 one)
2 - 1 = 1  01   (0 followed by 1 one)
4 - 1 = 3  011  (0 followed by 2 ones)
8 - 1 = 7  0111 (0 followed by 3 ones)
.          .
.          .
.          .

等等。

来到症结所在

当我们对数字x(它是一个数字)进行按位与操作时会发生什么
2 的幂,以及 x - 1

x 的 1 与 x - 1 的零对齐,并且 x 的所有零与 x 的 1 对齐>x - 1,导致按位与结果为 0。 这就是我们如何得到上面提到的单行答案是正确的。


进一步增加了上面接受的答案的美感 -

所以,我们现在有一个可以使用的财产:

当我们从任何数字中减去 1 时,那么在二进制表示中,最右边的 1 将变为 0,并且最右边的 1 右侧的所有零现在都将变为 1。

此属性的一个很棒的用途是找出 - 如何给定数字的二进制表示形式中存在许多 1? 对于给定整数 x 执行此操作的简短而有趣的代码是:

byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);

可以从概念证明的数字的另一个方面上面解释的是“每个正数都可以表示为2的幂和吗?”

是的,每个正数都可以表示为 2 的幂之和。对于任何数字,取其二进制表示形式。 例如:取号码 117

The binary representation of 117 is 1110101

Because  1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have  117     = 64      + 32     + 16    + 0    + 4   + 0  + 1

The following addendum to the accepted answer may be useful for some people:

A power of two, when expressed in binary, will always look like 1 followed by n zeroes where n is greater than or equal to 0. Ex:

Decimal  Binary
1        1     (1 followed by 0 zero)
2        10    (1 followed by 1 zero)
4        100   (1 followed by 2 zeroes)
8        1000  (1 followed by 3 zeroes)
.        .
.        .
.        .

and so on.

When we subtract 1 from these kind of numbers, they become 0 followed by n ones and again n is same as above. Ex:

Decimal    Binary
1 - 1 = 0  0    (0 followed by 0 one)
2 - 1 = 1  01   (0 followed by 1 one)
4 - 1 = 3  011  (0 followed by 2 ones)
8 - 1 = 7  0111 (0 followed by 3 ones)
.          .
.          .
.          .

and so on.

Coming to the crux

What happens when we do a bitwise AND of a number x, which is a
power of 2, and x - 1?

The one of x gets aligned with the zero of x - 1 and all the zeroes of x get aligned with ones of x - 1, causing the bitwise AND to result in 0. And that is how we have the single line answer mentioned above being right.


Further adding to the beauty of accepted answer above -

So, we have a property at our disposal now:

When we subtract 1 from any number, then in the binary representation the rightmost 1 will become 0 and all the zeroes to the right of that rightmost 1 will now become 1.

One awesome use of this property is in finding out - How many 1s are present in the binary representation of a given number? The short and sweet code to do that for a given integer x is:

byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);

Another aspect of numbers that can be proved from the concept explained above is "Can every positive number be represented as the sum of powers of 2?".

Yes, every positive number can be represented as the sum of powers of 2. For any number, take its binary representation. Ex: Take number 117.

The binary representation of 117 is 1110101

Because  1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have  117     = 64      + 32     + 16    + 0    + 4   + 0  + 1
徒留西风 2024-07-21 04:45:24
bool IsPowerOfTwo(ulong x)
{
    return x > 0 && (x & (x - 1)) == 0;
}
bool IsPowerOfTwo(ulong x)
{
    return x > 0 && (x & (x - 1)) == 0;
}
陪我终i 2024-07-21 04:45:24

这是一个简单的 C++ 解决方案:

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}

Here's a simple C++ solution:

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}
热风软妹 2024-07-21 04:45:24

发布问题后,我想到了以下解决方案:

我们需要检查二进制数字中的一位是否为 1。 因此,我们只需将数字一次右移一位,如果等于 1,则返回 true。如果在任何时候我们得到一个奇数 ((number & 1) == 1),我们知道结果是false。 事实证明(使用基准测试),对于(大)真值,这比原始方法稍快,而对于假值或小值,则快得多。

private static bool IsPowerOfTwo(ulong number)
{
    while (number != 0)
    {
        if (number == 1)
            return true;

        if ((number & 1) == 1)
            // number is an odd number and not 1 - so it's not a power of two.
            return false;

        number = number >> 1;
    }
    return false;
}

当然,格雷格的解决方案要好得多。

After posting the question I thought of the following solution:

We need to check if exactly one of the binary digits is one. So we simply shift the number right one digit at a time, and return true if it equals 1. If at any point we come by an odd number ((number & 1) == 1), we know the result is false. This proved (using a benchmark) slightly faster than the original method for (large) true values and much faster for false or small values.

private static bool IsPowerOfTwo(ulong number)
{
    while (number != 0)
    {
        if (number == 1)
            return true;

        if ((number & 1) == 1)
            // number is an odd number and not 1 - so it's not a power of two.
            return false;

        number = number >> 1;
    }
    return false;
}

Of course, Greg's solution is much better.

挽袖吟 2024-07-21 04:45:24
    bool IsPowerOfTwo(int n)
    {
        if (n > 1)
        {
            while (n%2 == 0)
            {
                n >>= 1;
            }
        }
        return n == 1;
    }

这里有一个通用算法,用于确定一个数字是否是另一个数字的幂。

    bool IsPowerOf(int n,int b)
    {
        if (n > 1)
        {
            while (n % b == 0)
            {
                n /= b;
            }
        }
        return n == 1;
    }
    bool IsPowerOfTwo(int n)
    {
        if (n > 1)
        {
            while (n%2 == 0)
            {
                n >>= 1;
            }
        }
        return n == 1;
    }

And here's a general algorithm for finding out if a number is a power of another number.

    bool IsPowerOf(int n,int b)
    {
        if (n > 1)
        {
            while (n % b == 0)
            {
                n /= b;
            }
        }
        return n == 1;
    }
微凉徒眸意 2024-07-21 04:45:24

现在在 .Net 6 中这非常容易。

using System.Numerics;

bool isPow2 = BitOperations.IsPow2(64); // sets true

这里是文档。

It's very easy in .Net 6 now.

using System.Numerics;

bool isPow2 = BitOperations.IsPow2(64); // sets true

Here is the documentation.

横笛休吹塞上声 2024-07-21 04:45:24
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
唠甜嗑 2024-07-21 04:45:24
int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

这真的很快。 检查所有 2^32 个整数大约需要 6 分 43 秒。

int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

This is really fast. It takes about 6 minutes and 43 seconds to check all 2^32 integers.

淡淡绿茶香 2024-07-21 04:45:24
return ((x != 0) && !(x & (x - 1)));

如果x是2的幂,则其唯一的1位位于位置n。 这意味着 x – 1 在位置 n 处有一个 0。 要了解原因,请回忆一下二进制减法的工作原理。 当从x中减1时,借位一直传播到位置n; 位 n 变为 0,所有低位变为 1。现在,由于 x 没有与 x – 1 相同的 1 位,x& (x – 1) 为 0,并且 !(x & (x – 1)) 为 true。

return ((x != 0) && !(x & (x - 1)));

If x is a power of two, its lone 1 bit is in position n. This means x – 1 has a 0 in position n. To see why, recall how a binary subtraction works. When subtracting 1 from x, the borrow propagates all the way to position n; bit n becomes 0 and all lower bits become 1. Now, since x has no 1 bits in common with x – 1, x & (x – 1) is 0, and !(x & (x – 1)) is true.

混吃等死 2024-07-21 04:45:24
bool isPowerOfTwo(int x_)
{
  register int bitpos, bitpos2;
  asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
  asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
  return bitpos > 0 && bitpos == bitpos2;
}
bool isPowerOfTwo(int x_)
{
  register int bitpos, bitpos2;
  asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
  asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
  return bitpos > 0 && bitpos == bitpos2;
}
有深☉意 2024-07-21 04:45:24

对于 2 的任何幂,以下也成立。

n&(-n)==n

注意:对于 n=0 失败,因此需要检查它
这样做的原因是:
-n 是 n 的 2s 补码。 -n 将使 n 的最右边设置位左侧的每一位与 n 相比翻转。 对于 2 的幂,只有一位设置位。

for any power of 2, the following also holds.

n&(-n)==n

NOTE: fails for n=0 , so need to check for it
Reason why this works is:
-n is the 2s complement of n. -n will have every bit to the left of rightmost set bit of n flipped compared to n. For powers of 2 there is only one set bit.

相权↑美人 2024-07-21 04:45:24

判断给定的数字是否是 2 的幂。

#include <math.h>

int main(void)
{
    int n,logval,powval;
    printf("Enter a number to find whether it is s power of 2\n");
    scanf("%d",&n);
    logval=log(n)/log(2);
    powval=pow(2,logval);

    if(powval==n)
        printf("The number is a power of 2");
    else
        printf("The number is not a power of 2");

    getch();
    return 0;
}

Find if the given number is a power of 2.

#include <math.h>

int main(void)
{
    int n,logval,powval;
    printf("Enter a number to find whether it is s power of 2\n");
    scanf("%d",&n);
    logval=log(n)/log(2);
    powval=pow(2,logval);

    if(powval==n)
        printf("The number is a power of 2");
    else
        printf("The number is not a power of 2");

    getch();
    return 0;
}
烟花易冷人易散 2024-07-21 04:45:24

如果一个数字仅包含 1 个设置位,则该数字是 2 的幂。 我们可以使用这个属性和通用函数 countSetBits 来判断一个数字是否是 2 的幂。

这是一个 C++ 程序:

int countSetBits(int n)
{
        int c = 0;
        while(n)
        {
                c += 1;
                n  = n & (n-1);
        }
        return c;
}

bool isPowerOfTwo(int n)
{        
        return (countSetBits(n)==1);
}
int main()
{
    int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
    for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
        printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
    return 0;
}

我们不需要显式检查 0 是否为 2 的幂,因为它对于 0 也返回 False。

输出

Num:0   Set Bits:0   is power of two: 0
Num:1   Set Bits:1   is power of two: 1
Num:2   Set Bits:1   is power of two: 1
Num:3   Set Bits:2   is power of two: 0
Num:4   Set Bits:1   is power of two: 1
Num:5   Set Bits:2   is power of two: 0
Num:15  Set Bits:4   is power of two: 0
Num:16  Set Bits:1   is power of two: 1
Num:22  Set Bits:3   is power of two: 0
Num:32  Set Bits:1   is power of two: 1
Num:38  Set Bits:3   is power of two: 0
Num:64  Set Bits:1   is power of two: 1
Num:70  Set Bits:3   is power of two: 0

A number is a power of 2 if it contains only 1 set bit. We can use this property and the generic function countSetBits to find if a number is power of 2 or not.

This is a C++ program:

int countSetBits(int n)
{
        int c = 0;
        while(n)
        {
                c += 1;
                n  = n & (n-1);
        }
        return c;
}

bool isPowerOfTwo(int n)
{        
        return (countSetBits(n)==1);
}
int main()
{
    int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
    for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
        printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
    return 0;
}

We dont need to check explicitly for 0 being a Power of 2, as it returns False for 0 as well.

OUTPUT

Num:0   Set Bits:0   is power of two: 0
Num:1   Set Bits:1   is power of two: 1
Num:2   Set Bits:1   is power of two: 1
Num:3   Set Bits:2   is power of two: 0
Num:4   Set Bits:1   is power of two: 1
Num:5   Set Bits:2   is power of two: 0
Num:15  Set Bits:4   is power of two: 0
Num:16  Set Bits:1   is power of two: 1
Num:22  Set Bits:3   is power of two: 0
Num:32  Set Bits:1   is power of two: 1
Num:38  Set Bits:3   is power of two: 0
Num:64  Set Bits:1   is power of two: 1
Num:70  Set Bits:3   is power of two: 0
素染倾城色 2024-07-21 04:45:24

这是我设计的另一种方法,在本例中使用 | 而不是 &

bool is_power_of_2(ulong x) {
    if(x ==  (1 << (sizeof(ulong)*8 -1) ) return true;
    return (x > 0) && (x<<1 == (x|(x-1)) +1));
}

Here is another method I devised, in this case using | instead of & :

bool is_power_of_2(ulong x) {
    if(x ==  (1 << (sizeof(ulong)*8 -1) ) return true;
    return (x > 0) && (x<<1 == (x|(x-1)) +1));
}
终止放荡 2024-07-21 04:45:24

我一直在阅读 Random.nextInt(intbound) 的文档,看到了这段不错的代码,它检查参数是否是 2 的幂,其中写着(代码的一部分):

if ((bound & -bound) == bound) // ie, bound is a power of 2   

让我们测试一下

for (int i=0; i<=8; i++) {
  System.out.println(i+" = " + Integer.toBinaryString(i));
}

>>
0 = 0
1 = 1
2 = 10
3 = 11
4 = 100
5 = 101
6 = 110
7 = 111
8 = 1000
// the left most 0 bits where cut out of the output

for (int i=-1; i>=-8; i--) {
  System.out.println(i+" = " + Integer.toBinaryString(i));
}

>>
-1 = 11111111111111111111111111111111
-2 = 11111111111111111111111111111110
-3 = 11111111111111111111111111111101
-4 = 11111111111111111111111111111100
-5 = 11111111111111111111111111111011
-6 = 11111111111111111111111111111010
-7 = 11111111111111111111111111111001
-8 = 11111111111111111111111111111000

你注意到了吗某物 ? 正负 2 次方数字在二进制表示中具有相反的位(负 2 次方数字是 1 的补码 的正 2 次方数。

如果我们对 X 和 -X 进行逻辑与(其中 X 是 2 次方数),我们会得到相同的正值 X :)

for (int i=0; i<=8; i++) {
  System.out.println(i + " & " + (-i)+" = " + (i & (-i)));
}

>>
0 & 0 = 0    <-
1 & -1 = 1   <-
2 & -2 = 2   <-
3 & -3 = 1
4 & -4 = 4   <-
5 & -5 = 1
6 & -6 = 2
7 & -7 = 1
8 & -8 = 8   <-

I've been reading the documentation for Random.nextInt(int bound) and saw this nice piece of code which checks whether the parameter is a power of 2, which says (part of the code) :

if ((bound & -bound) == bound) // ie, bound is a power of 2   

let's test it

for (int i=0; i<=8; i++) {
  System.out.println(i+" = " + Integer.toBinaryString(i));
}

>>
0 = 0
1 = 1
2 = 10
3 = 11
4 = 100
5 = 101
6 = 110
7 = 111
8 = 1000
// the left most 0 bits where cut out of the output

for (int i=-1; i>=-8; i--) {
  System.out.println(i+" = " + Integer.toBinaryString(i));
}

>>
-1 = 11111111111111111111111111111111
-2 = 11111111111111111111111111111110
-3 = 11111111111111111111111111111101
-4 = 11111111111111111111111111111100
-5 = 11111111111111111111111111111011
-6 = 11111111111111111111111111111010
-7 = 11111111111111111111111111111001
-8 = 11111111111111111111111111111000

did you notice something ? positive and negative Power 2 numbers have opposite bits in binary representation (negative power 2 numbers are 1's complement of positive power 2 numbers.

if we apply a logical AND over X and -X, where X is a Power 2 number, we get the same positive value X as a result :)

for (int i=0; i<=8; i++) {
  System.out.println(i + " & " + (-i)+" = " + (i & (-i)));
}

>>
0 & 0 = 0    <-
1 & -1 = 1   <-
2 & -2 = 2   <-
3 & -3 = 1
4 & -4 = 4   <-
5 & -5 = 1
6 & -6 = 2
7 & -7 = 1
8 & -8 = 8   <-
诗笺 2024-07-21 04:45:24

示例

0000 0001    Yes
0001 0001    No

算法

  1. 使用位掩码,将 NUM 变量除以二进制

  2. IF R > 0且L> 0:返回FALSE

  3. 否则,NUM 变为非零

  4. IF NUM = 1:返回 TRUE

  5. 否则,转到步骤 1

复杂性

时间 ~ O(log(d)) 其中 d 是二进制位数

Example

0000 0001    Yes
0001 0001    No

Algorithm

  1. Using a bit mask, divide NUM the variable in binary

  2. IF R > 0 AND L > 0: Return FALSE

  3. Otherwise, NUM becomes the one that is non-zero

  4. IF NUM = 1: Return TRUE

  5. Otherwise, go to Step 1

Complexity

Time ~ O(log(d)) where d is number of binary digits

挥剑断情 2024-07-21 04:45:24

如果您有 .NET Core,Markgravell 建议这个 3、系统。 Runtime.Intrinsics.X86.Popcnt.PopCount

public bool IsPowerOfTwo(uint i)
{
    return Popcnt.PopCount(i) == 1
}

单指令,比 (x != 0) && 更快 ((x & (x - 1)) == 0) 但便携性较差。

Mark gravell suggested this if you have .NET Core 3, System.Runtime.Intrinsics.X86.Popcnt.PopCount

public bool IsPowerOfTwo(uint i)
{
    return Popcnt.PopCount(i) == 1
}

Single instruction, faster than (x != 0) && ((x & (x - 1)) == 0) but less portable.

最美不过初阳 2024-07-21 04:45:24

.NET 6 中有一个衬垫

// IsPow2 evaluates whether the specified Int32 value is a power of two.
Console.WriteLine(BitOperations.IsPow2(128));            // True

There is a one liner in .NET 6

// IsPow2 evaluates whether the specified Int32 value is a power of two.
Console.WriteLine(BitOperations.IsPow2(128));            // True
蓝戈者 2024-07-21 04:45:24

改进@user134548的答案,无需位算术:

public static bool IsPowerOfTwo(ulong n)
{
    if (n % 2 != 0) return false;  // is odd (can't be power of 2)

    double exp = Math.Log(n, 2);
    if (exp != Math.Floor(exp)) return false;  // if exp is not integer, n can't be power
    return Math.Pow(2, exp) == n;
}

这适用于:

IsPowerOfTwo(9223372036854775809)

Improving the answer of @user134548, without bits arithmetic:

public static bool IsPowerOfTwo(ulong n)
{
    if (n % 2 != 0) return false;  // is odd (can't be power of 2)

    double exp = Math.Log(n, 2);
    if (exp != Math.Floor(exp)) return false;  // if exp is not integer, n can't be power
    return Math.Pow(2, exp) == n;
}

This works fine for:

IsPowerOfTwo(9223372036854775809)
樱花坊 2024-07-21 04:45:24

在这种方法中,您可以检查整数中是否只有 1 个设置位,并且该整数是否大于 1。 0(c++)。

bool is_pow_of_2(int n){
    int count = 0;
    for(int i = 0; i < 32; i++){
        count += (n>>i & 1);
    }
    return count == 1 && n > 0;
}

in this approach , you can check if there is only 1 set bit in the integer and the integer is > 0 (c++).

bool is_pow_of_2(int n){
    int count = 0;
    for(int i = 0; i < 32; i++){
        count += (n>>i & 1);
    }
    return count == 1 && n > 0;
}

雾里花 2024-07-21 04:45:24

Kotlin

fun isPowerOfTwo(n: Int): Boolean {
    return (n > 0) && (n.and(n-1) == 0)
}

fun isPowerOfTwo(n: Int): Boolean {
    if (n == 0) return false
    return (n and (n - 1).inv()) == n
}

inv 反转该值中的位。


注:
log2 解决方案不适用于大数字,例如 536870912 ->

import kotlin.math.truncate
import kotlin.math.log2

fun isPowerOfTwo(n: Int): Boolean {
    return (n > 0) && (log2(n.toDouble())) == truncate(log2(n.toDouble()))
}

Kotlin:

fun isPowerOfTwo(n: Int): Boolean {
    return (n > 0) && (n.and(n-1) == 0)
}

or

fun isPowerOfTwo(n: Int): Boolean {
    if (n == 0) return false
    return (n and (n - 1).inv()) == n
}

inv inverts the bits in this value.


Note:
log2 solution doesn't work for large numbers, like 536870912 ->

import kotlin.math.truncate
import kotlin.math.log2

fun isPowerOfTwo(n: Int): Boolean {
    return (n > 0) && (log2(n.toDouble())) == truncate(log2(n.toDouble()))
}
等风来 2024-07-21 04:45:24

我看到很多答案都建议返回 n && !(n & (n - 1)) 但根据我的经验,如果输入值为负数,它会返回错误值。
我将在这里分享另一种简单的方法,因为我们知道两个数字的幂只有一个设置位,所以我们只需计算设置位的数量,这将花费 O(log N) 时间。

while (n > 0) {
    int count = 0;
    n = n & (n - 1);
    count++;
}
return count == 1;

检查这篇文章计数。 设置位

I see many answers are suggesting to return n && !(n & (n - 1)) but to my experience if the input values are negative it returns false values.
I will share another simple approach here since we know a power of two number have only one set bit so simply we will count number of set bit this will take O(log N) time.

while (n > 0) {
    int count = 0;
    n = n & (n - 1);
    count++;
}
return count == 1;

Check this article to count no. of set bits

ゞ记忆︶ㄣ 2024-07-21 04:45:24

这也是另一种方法

package javacore;

import java.util.Scanner;

public class Main_exercise5 {
    public static void main(String[] args) {
        // Local Declaration
        boolean ispoweroftwo = false;
        int n;
        Scanner input = new Scanner (System.in);
        System.out.println("Enter a number");
        n = input.nextInt();
        ispoweroftwo = checkNumber(n);
        System.out.println(ispoweroftwo);
    }
    
    public static boolean checkNumber(int n) {
        // Function declaration
        boolean ispoweroftwo= false;
        // if not divisible by 2, means isnotpoweroftwo
        if(n%2!=0){
            ispoweroftwo=false;
            return ispoweroftwo;
        }
        else {
            for(int power=1; power>0; power=power<<1) {
                if (power==n) {
                    return true;
                }
                else if (power>n) {
                    return false;
                }
            }
        }
        return ispoweroftwo;
    }
}

This is another method to do it as well

package javacore;

import java.util.Scanner;

public class Main_exercise5 {
    public static void main(String[] args) {
        // Local Declaration
        boolean ispoweroftwo = false;
        int n;
        Scanner input = new Scanner (System.in);
        System.out.println("Enter a number");
        n = input.nextInt();
        ispoweroftwo = checkNumber(n);
        System.out.println(ispoweroftwo);
    }
    
    public static boolean checkNumber(int n) {
        // Function declaration
        boolean ispoweroftwo= false;
        // if not divisible by 2, means isnotpoweroftwo
        if(n%2!=0){
            ispoweroftwo=false;
            return ispoweroftwo;
        }
        else {
            for(int power=1; power>0; power=power<<1) {
                if (power==n) {
                    return true;
                }
                else if (power>n) {
                    return false;
                }
            }
        }
        return ispoweroftwo;
    }
}
兰花执着 2024-07-21 04:45:24

如果数字是 2 的幂,最多 64 个值,则返回此值(您可以在 for 循环条件中更改它(“6”表示 2^6 是 64);

const isPowerOfTwo = (number) => {
  let result = false;
  for (let i = 1; i <= 6; i++) {
    if (number === Math.pow(2, i)) {
      result = true;
    }
  }
  return result;
};

console.log(isPowerOfTwo(16));
console.log(isPowerOfTwo(10));

This one returns if the number is the power of two up to 64 value ( you can change it inside for loop condition ("6" is for 2^6 is 64);

const isPowerOfTwo = (number) => {
  let result = false;
  for (let i = 1; i <= 6; i++) {
    if (number === Math.pow(2, i)) {
      result = true;
    }
  }
  return result;
};

console.log(isPowerOfTwo(16));
console.log(isPowerOfTwo(10));

放我走吧 2024-07-21 04:45:24

有许多答案和发布的链接解释了为什么 n & (n-1) == 0 适用于 2 的幂,但我找不到任何解释为什么它不适用于非 2 的幂,所以我'我添加这个只是为了完整性。

对于 n = 1 (2^0 = 1), 1 & 0 = 0,所以我们很好。

对于奇数 n > 1,至少有 2 位为 1(最左边和最右边的位)。 现在 n 和 n-1 仅在最右边的位上有所不同,因此它们的 &-sum 最左边的位至少有一个 1,因此 n & (n-1) != 0:

n:          1xxxx1  for odd n > 1
n-1:        1xxxx0
            ------
n & (n-1):  1xxxx0 != 0

现在,即使 n 不是 2 的幂,我们也至少有 2 位 1(最左边和非最右边)。 这里,n 和 n-1 的差异最多为最右边的 1 位,因此它们的 &-sum 最左边的位也至少有一个 1:

        right-most 1 bit of n
                 v
n:          1xxxx100..00 for even n
n-1:        1xxxx011..11
            ------------
n & (n-1):  1xxxx000..00 != 0

There were a number of answers and posted links explaining why the n & (n-1) == 0 works for powers of 2, but I couldn't find any explanation of why it doesn't work for non-powers of 2, so I'm adding this just for completeness.

For n = 1 (2^0 = 1), 1 & 0 = 0, so we are fine.

For odd n > 1, there are at least 2 bits of 1 (left-most and right-most bits). Now n and n-1 will only differ by the right-most bit, so their &-sum will at least have a 1 on the left-most bit, so n & (n-1) != 0:

n:          1xxxx1  for odd n > 1
n-1:        1xxxx0
            ------
n & (n-1):  1xxxx0 != 0

Now for even n that is not a power of 2, we also have at least 2 bits of 1 (left-most and non-right-most). Here, n and n-1 will differ up to the right-most 1 bit, so their &-sum will also have at least a 1 on the left-most bit:

        right-most 1 bit of n
                 v
n:          1xxxx100..00 for even n
n-1:        1xxxx011..11
            ------------
n & (n-1):  1xxxx000..00 != 0
杯别 2024-07-21 04:45:24

我假设 1 是 2 的幂,确实如此,它是 2 的零次方

 bool IsPowerOfTwo(ulong testValue)
 {
  ulong bitTest = 1;
  while (bitTest != 0)
  {
    if (bitTest == testValue) return true;
    bitTest = bitTest << 1;
  }

  return false;
}

I'm assuming 1 is a power of two, which it is, it's 2 to the power of zero

 bool IsPowerOfTwo(ulong testValue)
 {
  ulong bitTest = 1;
  while (bitTest != 0)
  {
    if (bitTest == testValue) return true;
    bitTest = bitTest << 1;
  }

  return false;
}
情未る 2024-07-21 04:45:24

在 C 语言中,我测试了 i && !(i & (i - 1) 技巧,并将其与 __builtin_popcount(i) 进行比较,在 Linux 上使用 gcc,并使用 -mpopcnt 标志确保使用 CPU 的 POPCNT 指令我的测试程序计算了区间 [0, 2^31) 中 2 的幂的整数数量。

起初我以为i && !(i & (i - 1) 速度快了 10%,尽管我验证了在我使用__builtin_popcount的反汇编中使用了 POPCNT。

但是,我意识到我已经包含了if 语句和分支预测在位旋转版本上可能做得更好,我删除了 if 和 POPCNT 结果更快

Intel(R) Core(TM) i7-4771 CPU max 3.90GHz 。

Timing (i & !(i & (i - 1))) trick
30

real    0m13.804s
user    0m13.799s
sys     0m0.000s

Timing POPCNT
30

real    0m11.916s
user    0m11.916s
sys     0m0.000s

AMD Ryzen Threadripper 2950X 16 核处理器最高频率 3.50GHz

Timing (i && !(i & (i - 1))) trick
30

real    0m13.675s
user    0m13.673s
sys 0m0.000s

Timing POPCNT
30

real    0m13.156s
user    0m13.153s
sys 0m0.000s

请注意,这里 Intel CPU 的速度似乎比 AMD 稍慢,但 POPCNT 却比 AMD POPCNT 快得多; 提升。

t 提供尽可能

#include "stdio.h"

// Count # of integers that are powers of 2 up to (not including) 2^31;
int main() {
  int n;
  for (int z = 0; z < 20; z++){
      n = 0;
      for (unsigned long i = 0; i < 1<<30; i++) {
       #ifdef USE_POPCNT
        n += (__builtin_popcount(i)==1); // Was: if (__builtin_popcount(i) == 1) n++;
       #else
        n += (i && !(i & (i - 1)));  // Was: if (i && !(i & (i - 1))) n++;
       #endif
      }
  }

  printf("%d\n", n);
  return 0;
}

多的

gcc popcnt_test.c -O3 -o test.exe
gcc popcnt_test.c -O3 -DUSE_POPCNT -mpopcnt -o test-popcnt.exe

echo "Timing (i && !(i & (i - 1))) trick"
time ./test.exe

echo
echo "Timing POPCNT"
time ./test-opt.exe

In C, I tested the i && !(i & (i - 1) trick and compared it with __builtin_popcount(i), using gcc on Linux, with the -mpopcnt flag to be sure to use the CPU's POPCNT instruction. My test program counted the # of integers in the interval [0, 2^31) that were a power of two.

At first I thought that i && !(i & (i - 1) was 10% faster, even though I verified that POPCNT was used in the disassembly where I used__builtin_popcount.

However, I realized that I had included an if statement, and branch prediction was probably doing better on the bit twiddling version. I removed the if and POPCNT ended up faster, as expected.

Results:

Intel(R) Core(TM) i7-4771 CPU max 3.90GHz

Timing (i & !(i & (i - 1))) trick
30

real    0m13.804s
user    0m13.799s
sys     0m0.000s

Timing POPCNT
30

real    0m11.916s
user    0m11.916s
sys     0m0.000s

AMD Ryzen Threadripper 2950X 16-Core Processor max 3.50GHz

Timing (i && !(i & (i - 1))) trick
30

real    0m13.675s
user    0m13.673s
sys 0m0.000s

Timing POPCNT
30

real    0m13.156s
user    0m13.153s
sys 0m0.000s

Note that here the Intel CPU seems slightly slower than AMD with the bit twiddling, but has a much faster POPCNT; the AMD POPCNT doesn't provide as much of a boost.

popcnt_test.c:

#include "stdio.h"

// Count # of integers that are powers of 2 up to (not including) 2^31;
int main() {
  int n;
  for (int z = 0; z < 20; z++){
      n = 0;
      for (unsigned long i = 0; i < 1<<30; i++) {
       #ifdef USE_POPCNT
        n += (__builtin_popcount(i)==1); // Was: if (__builtin_popcount(i) == 1) n++;
       #else
        n += (i && !(i & (i - 1)));  // Was: if (i && !(i & (i - 1))) n++;
       #endif
      }
  }

  printf("%d\n", n);
  return 0;
}

Run tests:

gcc popcnt_test.c -O3 -o test.exe
gcc popcnt_test.c -O3 -DUSE_POPCNT -mpopcnt -o test-popcnt.exe

echo "Timing (i && !(i & (i - 1))) trick"
time ./test.exe

echo
echo "Timing POPCNT"
time ./test-opt.exe
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文