It has to do with the way an integer is stored in binary.
&
is a bit-operator which is an AND
gate for the bits left and right of it. And works like this for two bits:
1 & 1 => 1
1 & 0 => 0
0 & 1 => 0
0 & 0 => 0
Due to the binary representation every power of 2 is represented with a 1
at a position i
and all zeroes on all positions < i
. Because of that and the way AND
works we only get a 1
bit if we have 1
at both positions left and right. So for every power of two we have a single 1
and the rest all zeroes and for every value that is not a power of two will use <= i-1
bits, at least one of which is different from zero.
The result of the operation n & (n - 1)
, if we have a power of two power_of_two & power_of_two - 1
, will always return 0
which is a falsy
value in Python so the else
branch will be triggered. For every value that is not a power of two not_power_of_two & not_power_of_two - 1
will return something != 0
which is a truthy
value in Python hence "NO"
is returned.
Probably this example is easier to understand that all the text above:
Input |
Binary repr. input |
Binary repr. input -1 |
Result AND (&) binary |
Result AND decimal |
Python truthy/ falsy |
0 |
0b0000 |
0b1111 |
0b0000 |
0 |
falsy |
1 |
0b0001 |
0b0000 |
0b0000 |
0 |
falsy |
2 |
0b0010 |
0b0001 |
0b0000 |
0 |
falsy |
3 |
0b0011 |
0b0010 |
0b0010 |
2 |
truthy |
4 |
0b0100 |
0b0011 |
0b0000 |
0 |
falsy |