Find the next larger number with the same number of bits set
I am working on a problem, when I am assigned a number n, I have to find the next larger item with the same number of set bits. While searching the web, I found an interesting piece of code that does this in a few lines of code (BIT MAGIC) here :
unsigned nexthi_same_count_ones(unsigned a) {
/* works for any word length */
unsigned c = (a & -a);
unsigned r = a+c;
return (((r ^ a) >> 2) / c) | r);
}
But I want to understand the basic logic of the algorithm that it will always work. All edge cases will be handled properly.
Can someone explain the logic in simple steps.
thank
source to share
In the next higher number, the leftmost 1
rightmost run 1
swaps with the 0
left, and the rest 1
move to the far right.
- The code isolates the lowest
1
, - adds it to
a
(doing it brings the ripple to the next higher one0
, inverting all those bits) - The ex-or gets the least significant mileage of these, pushed one space to the left.
- Offset to the right of two positions takes the left border one position to the right of the original (leaving room for this
0
from the top position), - Dividing by the smallest
1
gives room for more0
-bits more than the right enda
.
source to share
Let's say we have a bit pattern like
111100111 - decimal representation of 487
to generate the next highest integer while keeping the number 0 and 1 as in the input, we need to find the first 0 bit to the right of the input, followed by 1, and we need to switch that bit to 1. Then we need to decrease the 1 to the right from this flip point by 1 to compensate for the bit we switched from 0 to 1.
our new bit pattern will become 111101011 - 491 in decimal (we kept the bit set and not set on the input)
int getNextNumber(int input)
{
int flipPosition=0;
int trailingZeros=0;
int trailingOnes=0;
int copy = input;
//count trailing zeros
while(copy != 0 && (copy&1) == 0 )
{
++trailingZeros;
//test next bit
copy = copy >> 1;
}
//count trailing ones
while(copy != 0 && (copy&1) == 1 )
{
++trailingOnes;
//test next bit
copy = copy >> 1;
}
//if we have no 1 we cannot form another patter with the same number of 1's
//which will increment the input, or if we have leading consecutive
//zero followed by consecutive 1 up to the maximum bit size of a int
//we cannot increase the input whilst preserving the no of 0 and
//1 in the original bit pattern
if(trailingZeros + trailingOnes == 0 || trailingZeros + trailingOnes == 31)
return -1;
//flip first 0 followed by a 1 found from the right of the bit pattern
flipPosition = trailingZeros + trailingOnes+1;
input |= 1<<(trailingZeros+trailingOnes);
//clear fields to the right of the flip position
int mask = ~0 << (trailingZeros+trailingOnes);
input &= mask;
//insert a bit pattern to the right of the flop position that will contain
//one less 1 to compensate for the bit we switched from 0 to 1
int insert = flipPosition-1;
input |= insert;
return input;
}
source to share