Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count number of times each bit is set in a range of integers

Given a range of integers from M to N, where M and N might not be a powers of 2. Is there an efficient way to count the number of times each bit is set?

For example the range 0 to 10

0   0000
1   0001
2   0010
3   0011
4   0100
5   0101
6   0110
7   0111
8   1000
9   1001
10  1010

I'd like the counts for the number of time each bit is set in each column which would be 3,4,5,5 in this case.

like image 629
Jack Nock Avatar asked Jun 25 '12 02:06

Jack Nock


People also ask

How do you find the number of set bits in an integer?

We can also use bitset::count(), an inbuilt STL in C++ that returns the count of the total number of set bits in an integer.

What is the set bits of an integer?

The number of set bits in an integer is the number of 1s in the binary representation of the integer.


1 Answers

Each bit level has a pattern consisting of 2^power 0s followed by 2^power 1s.

So there are three cases:

  1. When M and N are such that M = 0 mod 2^(power+1) and N = 2^(power+1)-1 mod 2^(power+1). In this case the answer is simply (N-M+1) / 2

  2. When M and N are such that both M and N = the same number when integer divided by 2^(power+1). In this case there are a few subcases:

    1. Both M and N are such that both M and N = the same number when integer divided by 2^(power). In this case if N < 2^(power) mod 2^(power+1) then the answer is 0, else the answer is N-M+1
    2. Else they are different, in this case the answer is N - (N/2^(power+1))*2^(power+1) + 2**(power) (integer division) if N > 2^(power) mod 2^(power+1), else the answer is (M/2^(power+1))*2^(power+1) - 1 - M
  3. Last case is where M and N = different numbers when integer divided by 2^(power+1). This this case you can combine the techniques of 1 and 2. Find the number of numbers between M and (M/(2^(power+1)) + 1)*(2^(power+1)) - 1. Then between (M/(2^(power+1)) + 1)*(2^(power+1)) and (N/(2^(power+1)))*2^(power+1)-1. And finally between (N/(2^(power+1)))*2^(power+1) and N.

If this answer has logical bugs in it, let me know, it's complicated and I may have messed something up slightly.

UPDATE:

python implementation

def case1(M, N):
  return (N - M + 1) // 2

def case2(M, N, power):
  if (M > N):
    return 0
  if (M // 2**(power) == N // 2**(power)):
    if (N % 2**(power+1) < 2**(power)):
      return 0
    else:
      return N - M + 1
  else:
    if (N % 2**(power+1) >= 2**(power)):
      return N - (getNextLower(N,power+1) + 2**(power)) + 1
    else:
      return getNextHigher(M, power+1) - M


def case3(M, N, power):
  return case2(M, getNextHigher(M, power+1) - 1, power) + case1(getNextHigher(M, power+1), getNextLower(N, power+1)-1) + case2(getNextLower(N, power+1), N, power)

def getNextLower(M, power):
  return (M // 2**(power))*2**(power)

def getNextHigher(M, power):
  return (M // 2**(power) + 1)*2**(power)

def numSetBits(M, N, power):
  if (M % 2**(power+1) == 0 and N % 2**(power+1) == 2**(power+1)-1):
    return case1(M,N)
  if (M // 2**(power+1) == N // 2**(power+1)):
    return case2(M,N,power)
  else:
    return case3(M,N,power)

if (__name__ == "__main__"):
  print numSetBits(0,10,0)
  print numSetBits(0,10,1)
  print numSetBits(0,10,2)
  print numSetBits(0,10,3)
  print numSetBits(0,10,4)
  print numSetBits(5,18,0)
  print numSetBits(5,18,1)
  print numSetBits(5,18,2)
  print numSetBits(5,18,3)
  print numSetBits(5,18,4)
like image 64
OmnipotentEntity Avatar answered Dec 19 '22 19:12

OmnipotentEntity