Friday, August 28, 2015

Number of 1 Bits

Problem Description
Calculate Hamming Weight of an unsigned integer.
NOTE: Hamming Weight of an unsigned integer is the number of 1 bits in its unsigned representation.
Solution
In order to solve the problem, we iteratively check the right most bit if it is 1, then shift all the bits to the right 1 bit (i.e divide it by 2). The code for this implementation is in part I (java) & part II (C++).

We can also do a trick here. It's good to know that we can drop the rightmost set bit by the operation (n&(n-1)).

It is in part III & IV. In part V, we see different naive implementations.
I. Java
public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        
        while(n != 0){
            if((n & 1) == 1) count++;
            n >>>= 1;
        }
        return count;
    }
}
II. C++
class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n != 0){
            if(n & 1) count++;
            n >>=1;
        }
        return count;
    }
};
III. Java with (n & (n-1)) Solution
public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        while(n!=0){
            n &= (n-1);
            count++;
        }
        return count;
    }
}

IV. C++ with (n & (n-1)) Solution
class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
    
        while (n) {
            n &= (n - 1);
            count++;
        }
    
        return count;
    }
};
V. Naive Java Solutions (From Wiki: Hamming Weight with modification)
public class Solution {
    
    public int hammingWeight(int n) {
        return popcount_3(n);   
    }
    // you need to treat n as an unsigned value
    final int m1  = 0x55555555; //binary: 0101...
    final int m2  = 0x33333333; //binary: 00110011..
    final int m4  = 0x0f0f0f0f; //binary:  4 zeros,  4 ones ...
    final int m8  = 0x00ff00ff; //binary:  8 zeros,  8 ones ...
    final int m16 = 0x0000ffff; //binary: 16 zeros, 16 ones ...
    final int hff = 0xffffffff; //binary: all ones
    final int h01 = 0x01010101; //the sum of 256 to the power of 0,1,2,3...
    
    //This is a naive implementation, shown for comparison,
    //and to help in understanding the better functions.
    //It uses 24 arithmetic operations (shift, add, and).
    int popcount_1(int x) {
        x = (x & m1 ) + ((x >>>  1) & m1 ); //put count of each  2 bits into those  2 bits 
        x = (x & m2 ) + ((x >>>  2) & m2 ); //put count of each  4 bits into those  4 bits 
        x = (x & m4 ) + ((x >>>  4) & m4 ); //put count of each  8 bits into those  8 bits 
        x = (x & m8 ) + ((x >>>  8) & m8 ); //put count of each 16 bits into those 16 bits 
        x = (x & m16) + ((x >>> 16) & m16); //put count of each 32 bits into those 32 bits 
        return x;
    }
    
    //This uses fewer arithmetic operations than any other known  
    //implementation on machines with slow multiplication.
    //It uses 17 arithmetic operations.
    int popcount_2(int x) {
        x -= (x >>> 1) & m1;             //put count of each 2 bits into those 2 bits
        x = (x & m2) + ((x >>> 2) & m2); //put count of each 4 bits into those 4 bits 
        x = (x + (x >>> 4)) & m4;        //put count of each 8 bits into those 8 bits 
        x += x >>>  8;  //put count of each 16 bits into their lowest 8 bits
        x += x >>> 16;  //put count of each 32 bits into their lowest 8 bits
        return x & 0x7f;
    }
    
    //This uses fewer arithmetic operations than any other known  
    //implementation on machines with fast multiplication.
    //It uses 12 arithmetic operations, one of which is a multiply.
    int popcount_3(int x) {
        x -= (x >>> 1) & m1;             //put count of each 2 bits into those 2 bits
        x = (x & m2) + ((x >>> 2) & m2); //put count of each 4 bits into those 4 bits 
        x = (x + (x >>> 4)) & m4;        //put count of each 8 bits into those 8 bits 
        return (x * h01)>>>24;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
    }
}

No comments:

Post a Comment