简体   繁体   中英

Finding a numbers with the largest/smallest number of bits set

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM