Given a range of integers, how do I find the numbers within the range with the largest and the lowest number of bits set?
For example, given the range [32, 65]
, 63 has the largest number of bits set (ie six, because the binary representation is 111111
) and 32 and 64 have the lowest (ie one, because the binary representation are 100000
and 1000000
).
Has to work fast for very large numbers/ranges (2^50).
Try to find the highest power of 2 that is within the range. This can be done by taking the upper bound and ANDing it with itself minus one in a loop, like:
temp = upper_bound;
while( (temp & (temp-1)) != 0) {
temp = temp & (temp-1);
}
if(temp < lower_bound) {
// No power of 2 found within range
}
If no power of 2 within the range is found by the previous step; you would've found a power of 2 that is not in range. Clear the corresponding bit in the upper and lower bounds and recurse; like:
void find_bits(unsigned int lower_bound, unsigned int upper_bound, unsigned int extra_bits) {
unsigned int temp = upper_bound;
while( (temp & (temp-1)) != 0) {
temp = temp & (temp-1);
}
if(temp < lower_bound) {
find_bits(lower_bound ^ temp, upper_bound ^ temp, extra_bits + 1);
return;
}
If zero is within the range, then the smallest number of set bits is zero (from the number zero). Otherwise, the smallest number of set bits is one (from any power of 2 within range, including the highest power of 2 you found). Don't forget to account for any extra bits that were previously cleared:
if(lower_bound == 0) {
least_set_bits = 0 + extra_bits;
} else {
least_set_bits = 1 + extra_bits;
}
If the highest power of 2 within range minus 1 is also within the range, then the largest number of set bits will be however many bits is in highest power of 2 within range minus 1. Otherwise, the upper bound must have been the same as the lower bound and therefore the largest number of set bits is equal to the smallest number of set bits:
if(temp - 1 < lower_bound) {
most_set_bits = least_set_bits;
} else {
temp--;
most_set_bits = 0;
while(temp > 0) {
temp >>= 1;
most_set_bits++;
}
most_set_bits += extra_bits;
}
All of the above combined (and untested and probably buggy; and definitely not able to handle some corner cases - eg if the range is [0, 0]):
void find_bits(unsigned int lower_bound, unsigned int upper_bound, unsigned int extra_bits) {
unsigned int temp = upper_bound;
unsigned int least_set_bits;
unsigned int most_set_bits;
while( (temp & (temp-1)) != 0) {
temp = temp & (temp-1);
}
if(temp < lower_bound) {
find_bits(lower_bound ^ temp, upper_bound ^ temp, extra_bits + 1);
return;
}
if(lower_bound == 0) {
least_set_bits = 0 + extra_bits;
} else {
least_set_bits = 1 + extra_bits;
}
if(temp - 1 < lower_bound) {
most_set_bits = least_set_bits;
} else {
temp--;
most_set_bits = 0;
while(temp > 0) {
temp >>= 1;
most_set_bits++;
}
most_set_bits += extra_bits;
}
printf("Least set bits is %u, most set bits is %u.\n", least_set_bits, most_set_bits);
}
Given the range [ lower
, upper
] with unsigned
lower
and upper
, let diff = lower ^ upper
be the bits that are different in lower
and upper
.
If diff
is zero, the lower
and upper
are identical, so the least number of bits and the greatest number of bits set in the range is the number of bits set in lower
.
Otherwise, let n
be the number of the greatest bit set in diff
, starting counting from 0 for the least significant bit. Let mask = (2u << n) - 1
be a mask for the bits up to and including bit n
. (Note 2u
is correct.) Partition lower
and upper
into shared high bits and separate low bits:
shared = lower & ~mask;
lower &= mask;
upper &= mask;
Count the bits set in shared
. They are necessarily set in any value in the original [ lower
, upper
]. Below, we solve for the new lower
and upper
. Then the solution for the original values is obtained by adding the number of bits set in shared
.
If lower
is zero, the least number of bits set is zero, since 0 is in [ lower
, upper
], Otherwise, it is one, since 1u << n
is in [ lower
, upper
].
If upper
equals mask
, the greatest number of bits set is n+1
, the number of bits set in mask
. Otherwise, it is n
, since (1u << n) - 1
is in [ lower
, upper
].
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.