How does this bitwise operation check for a power of 2?

CMathBit Manipulation

C Problem Overview


I'm looking at some code which should be trivial -- but my math is failing me miserably here.

Here's a condition that checks if a number if a power of 2 using the following:

if((num != 1) && (num & (num - 1))) { /* make num pow of 2 */ }

My question is, how does using a bitwise AND between num and num - 1 determine if a number is a power of 2?

C Solutions


Solution 1 - C

Any power of 2 minus 1 is all ones: (2 N - 1 = 111....b)

2 = 2^1.  2-1 = 1 (1b)
4 = 2^2.  4-1 = 3 (11b)
8 = 2^3.  8-1 = 7 (111b)

Take 8 for example. 1000 & 0111 = 0000

So that expression tests if a number is NOT a power of 2.

Solution 2 - C

Well, the first case will check for 20 == 1.

For the other cases the num & (num - 1) comes into play:

That's saying if you take any number, and mask off the bits from one lower, you'll get one of two cases:

  1. if the number is a power of two already, then one less will result in a binary number that only has the lower-order bits set. Using & there will do nothing.
  • Example with 8: 0100 & (0100 - 1) --> (0100 & 0011) --> 0000
  1. if the number is not a power of two already, then one less will not touch the highest bit, so the result will be at least the largest power of two less than num.
  • Example with 3: 0011 & (0011 - 1) --> (0011 & 0010) --> 0010

  • Example with 13: 1101 & (1101 - 1) --> (1101 & 1100) --> 1100

So the actual expression finds everything that isn't a power of two, including 20.

Solution 3 - C

Well,

if you have X = 1000 then x-1 = 0111. And 1000 && 0111 is 0000.

Each number X that is a power of 2 has an x-1 that has ones on the position x has zeroes. And a bitwise and of 0 and 1 is always 0.

If the number x is not a power of two, for example 0110. The x-1 is 0101 and the and gives 0100.

For all combinbations within 0000 - 1111 this leads to

   X  X-1 X && X-1  
0000 1111 0000   
0001 0000 0000 
0010 0001 0000
0011 0010 0010
0100 0011 0000
0101 0100 0100
0110 0101 0100
0111 0110 0110
1000 0111 0000
1001 1000 1000
1010 1001 1000
1011 1010 1010
1100 1011 1000
1101 1100 1100
1110 1101 1100
1111 1110 1110

And there is no need for a separate check for 1.

Solution 4 - C

I prefer this approach that relies on two's complement:

bool checkPowTwo(int x){
    return (x & -x) == x;
}

Solution 5 - C

Explained here nicely

Also the expression given considers 0 to be a power of 2. To fix that use !(x & (x - 1)) && x; instead.

Solution 6 - C

It determines whether integer is power of 2 or not. If (x & (x-1)) is zero then the number is power of 2.

For example, let x be 8 (1000 in binary); then x-1 = 7 (0111).

if    1000
  &   0111
---------------
      0000

C program to demonstrate:

#include <stdio.h>

void main()
{
    int a = 8;
    if ((a&(a-1))==0)
    {
        printf("the bit is power of 2  \n");
    }
    else 
    {
        printf("the bit is not power of 2\n");
    }
}

This outputs the bit is power of 2.

#include <stdio.h>

void main()
{
    int a = 7;
    if ((a&(a-1))==0)
    {
        printf("the bit is power of 2  \n");
    }
    else 
    {
        printf("the bit is not power of 2\n");
    }
}

This outputs the bit is not power of 2.

Solution 7 - C

Suppose n is the given number, if n is power of 2 (n && !(n & (n-1)) will return 1 else return 0

Solution 8 - C

#include <stdio.h>
void powerof2(int a);
int a;

int main()
{
    while(1)
    {
       printf("Enter any no. and Check  whether no is power of 2 or no \n");
       scanf("%d",&a);
       powerof2(a);
    }
}
void powerof2(int a)
{
    int count = 0;
    int b=0;
   while(a)
   {
     b=a%2;
     a=a/2;
     if(b == 1)
        {  count++;  }
   }
  if(count == 1)
   {
      printf("power of 2\n");
   }
  else
    printf("not power of 2\n");
}

Solution 9 - C

When you decrement a positive integer by 1:

  1. if it is zero, you get -1.
  2. if its least significant bit is 1, this bit is set to 0, the other bits are unchanged.
  3. otherwise, all the low order 0 bits are set to 1 and the lowest 1 bit if set to 0, the other bits are unchanged.

Case 1: x & (x - 1) is 0, yet x is not a power of 2, trivial counter example.

Cases 2 and 3: if x and x-1 have no bits in common, it means the other bits in both of the above cases are all zero, hence the number has a single 1 bit, hence it is a power of 2.

If x is negative, this test does not work for two's complement representation of signed integers as either decrementing overflows or x and x-1 have at least the sign bit in common, which means x & (x-1) is not zero.

To test for a power of 2 the code should be:

int is_power_of_2(unsigned x) {
    return x && !(x & (x - 1));
}

Solution 10 - C

Following program in C will find out if the number is power of 2 and also find which power of 2, the number is.

#include<stdio.h>
void main(void)
{
    unsigned int a;
    unsigned int count=0
    unsigned int check=1;
    unsigned int position=0;
    unsigned int temp;
    //get value of a
    for(i=0;i<sizeof(int)*8;i++)//no of bits depend on size of integer on that machine
    {
        temp = a&(check << i);
        if(temp)
        {
            position = i;
            count++;
        }
    }
    if(count == 1)
    {
        printf("%d is 2 to the power of %d",a,position);
    }
    else
    {
        printf("Not a power of 2");
    }
}

There are other ways to do this:- if a number is a power of 2, only 1 bit will be set in the binary format

for example 8 is equivalent to 0x1000, substracting 1 from this, we get 0x0111.

End operation with the original number(0x1000) gives 0.

if that is the case, the number is a power of 2

    void IsPowerof2(int i)
    {
    if(!((i-1)&1))
    {
    printf("%d" is a power of 2, i);
    }
    }

another way can be like this:-

If we take complement of a number which is a power of 2,

for example complement of 8 i.e 0x1000 , we get 0x0111 and add 1 to it, we get

the same number, if that is the case, that number is a power of 2

    void IsPowerof2(int i)
    {
    if(((~1+1)&i) == 1)
    {
    printf("%d" is a power of 2,i):
    }
    }                                                     

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCoocoo4CocoaView Question on Stackoverflow
Solution 1 - CeduffyView Answer on Stackoverflow
Solution 2 - ClavinioView Answer on Stackoverflow
Solution 3 - CToon KrijtheView Answer on Stackoverflow
Solution 4 - CA. MashreghiView Answer on Stackoverflow
Solution 5 - CrohitttView Answer on Stackoverflow
Solution 6 - CsanjeevView Answer on Stackoverflow
Solution 7 - CShobhit SrivastavaView Answer on Stackoverflow
Solution 8 - CRohit GuptaView Answer on Stackoverflow
Solution 9 - CchqrlieView Answer on Stackoverflow
Solution 10 - CNanobrainsView Answer on Stackoverflow