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?
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); thenx-1
= 7 (0111
).C program to demonstrate:
This outputs
the bit is power of 2
.This outputs
the bit is not power of 2
.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:
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.0100 & (0100 - 1)
-->(0100 & 0011)
-->0000
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.
Following program in C will find out if the number is power of 2 and also find which power of 2, the number is.
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
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
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
And there is no need for a separate check for 1.
Explained here nicely
Also the expression given considers 0 to be a power of 2. To fix that use
!(x & (x - 1)) && x;
instead.Any power of 2 minus 1 is all ones: (2 N - 1 = 111....b)
Take 8 for example. 1000 & 0111 = 0000
So that expression tests if a number is NOT a power of 2.