Calculating Hamming weight efficiently in matlab

bit-manipulation, bitstring, hammingweight, matlab

Solution

I'd be interested to see how fast this solution is:

function r = count_bits(n)

shifts = [-1, -2, -4, -8, -16];
masks = [1431655765, 858993459, 252645135, 16711935, 65535];

r = n;
for i=1:5
   r = bitand(bitshift(r, shifts(i)), masks(i)) + ...
      bitand(r, masks(i));
end

Going back, I see that this is the 'parallel' solution given on the bithacks page.

Problem

Given a MATLAB uint32 to be interpreted as a bit string, what is an efficient and concise way of counting how many nonzero bits are in the string? I have a working, naive approach which loops over the bits, but that's too slow for my needs. (A C++ implementation using std::bitset count() runs almost instantly). I've found a pretty nice page listing various bit counting techniques, but I'm hoping there is an easy MATLAB-esque way. http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive Update #1 Just implemented the Brian Kernighan algorithm as follows: ``` w = 0; while ( bits > 0 ) bits = bitand( bits, bits-1 ); w = w + 1; end ``` Performance is still crappy, over 10 seconds to compute just 4096^2 weight calculations. My C++ code using count() from std::bitset does this in subsecond time. Update #2 Here is a table of run times for the techniques I've tried so far. I will update it as I get additional ideas/suggestions. ``` Vectorized Scheiner algorithm => 2.243511 sec Vectorized Naive bitget loop => 7.553345 sec Kernighan algorithm => 17.154692 sec length( find( bitget( val, 1:32 ) ) ) => 67.368278 sec nnz( bitget( val, 1:32 ) ) => 349.620259 sec Justin Scheiner's algorithm, unrolled loops => 370.846031 sec Justin Scheiner's algorithm => 398.786320 sec Naive bitget loop => 456.016731 sec sum(dec2bin(val) == '1') => 1069.851993 sec ``` Comment: The dec2bin() function in MATLAB seems to be very poorly implemented. It runs extremely slow. Comment: The "Naive bitget loop" algorithm is implemented as follows: ``` w=0; for i=1:32 if bitget( val, i ) == 1 w = w + 1; end end ``` Comment: The loop unrolled version of Scheiner's algorithm looks as follows: ``` function w=computeWeight( val ) w = val; w = bitand(bitshift(w, -1), uint32(1431655765)) + ... bitand(w, uint32(1431655765)); w = bitand(bitshift(w, -2), uint32(858993459)) + ... bitand(w, uint32(858993459)); w = bitand(bitshift(w, -4), uint32(252645135)) + ... bitand(w, uint32(252645135)); w = bitand(bitshift(w, -8), uint32(16711935)) + ... bitand(w, uint32(16711935)); w = bitand(bitshift(w, -16), uint32(65535)) + ... bitand(w, uint32(65535)); ```

Original source