optimal Hamming Distance implementation

Anyone know how to optimally implement a Hamming distance and weight function?

My first stab is this code:

/**

* Calculates the <b>Hamming distance</b> between 2 ints.

* The ints are viewed as binary strings, so the result is the number of bits where the 2 ints differ.

* In particular, this method simply returns <code>{@link #hammingWeight hammingWeight}( i1 ^ i2 )</code>.

*

* @see <a href="http://en.wikipedia.org/wiki/Hamming_distance">Wikipedia article on Hamming Distance</a>

*/

publicstaticint hammingDistance(int bits1,int bits2){

return hammingWeight( bits1 ^ bits2 );

}

/**

* Calculates the <b>Hamming weight</b> of an int.

* The int is viewed as a binary string, so the result is the number of bits equal to 1.

*

* @see <a href="http://en.wikipedia.org/wiki/Hamming_distance">Wikipedia article on Hamming Distance</a>

*/

publicstaticint hammingWeight(int bits){

int weight = 0;

for (int i = 0; i < 32; i++){

int lsb = bits & 1;// bitwise AND with 1 leaves just the least significant bit of i

weight += lsb;// add lsb to the result

bits >>>= 1;// unsigned right shift i by 1 bit so that the next iteration detects the next bit; could use signed shift too (any performance difference?)

}

return weight;

}

I think that that code is corrrect, and below is my test code:

privatestaticvoid test_hamming()throws Exception{

System.out.println();

System.out.println("test_hamming:");

if (hammingWeight(Integer.MIN_VALUE) != 1)thrownew Exception("hammingWeight(Integer.MIN_VALUE) = " + hammingWeight(Integer.MIN_VALUE) +" != 1");

if (hammingWeight(Integer.MAX_VALUE) != 31)thrownew Exception("hammingWeight(Integer.MAX_VALUE) = " + hammingWeight(Integer.MAX_VALUE) +" != 31");

if (hammingWeight(0) != 0)thrownew Exception("hammingWeight(0) = " + hammingWeight(0) +" != 0");

if (hammingWeight(1) != 1)thrownew Exception("hammingWeight(1) = " + hammingWeight(1) +" != 1");

// could likewise do all the other powers of 2...

if (hammingWeight(15) != 4)thrownew Exception("hammingWeight(15) = " + hammingWeight(15) +" != 4");

if (hammingDistance(Integer.MIN_VALUE, Integer.MAX_VALUE) != 32)thrownew Exception("hammingDistance(Integer.MIN_VALUE, Integer.MAX_VALUE) = " + hammingDistance(Integer.MIN_VALUE, Integer.MAX_VALUE) +" != 32");

if (hammingDistance(0, 1) != 1)thrownew Exception("hammingDistance(0, 1) = " + hammingDistance(0, 1) +" != 1");

if (hammingDistance(15, 16) != 5)thrownew Exception("hammingDistance(15, 16) = " + hammingDistance(15, 16) +" != 5");

System.out.println("All tests passed");

}

My question concerns the algorithm inside the above hammingWeight method: is there any way to count the number of bits set to 1 besides doing a sequential examination like that method currently does?

Any clever bit twiddling logic that I am ignorant of?

[5406 byte] By [bbatmana] at [2007-10-2 13:38:08]
# 1

I believe that the classical O(lgN) vs O(n) is this:

static int bitCount(int foo){

int m = 0x55555555;

int r = (foo&m) + ((foo>>>1)&m);

m = 0x33333333;

r = (r&m) + ((r>>>2)&m);

m = 0x0F0F0F0F;

r = (r&m) + ((r>>>4)&m);

m = 0x00FF00FF;

r = (r&m) + ((r>>>8)&m);

m = 0x0000FFFF;

return r = (r&m) + ((r>>>16)&m);

}

But I just typed it in, you should check it before trusting it.

marlin314a at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 2

I too am not sure if the code you typed in is correct, but it inspired me to google "0x55555555" and that turned me on to tons of sources that discuss this topic, which apparently is most commonly known as "bit counting" (and not Hamming weight, which was what my original search was on).

Your code is one possibility for a fast approach.

Another is a table lookup, with the usual choice being a 256 element table that lists the bit counts of all possible bytes. For an int, you get each of its 4 bytes by shifting and use them as indices directly into this table (and for java, you will need to take make sure that the byte is unsigned by doing & 0xFF with it).

And if your machine does really fast int multiplies (e.g. apparently some of AMD's latest cpus are like this), there is possibly an even faster algorithm that uses a single multiply.

The best single source for this type of computation that I found is

http://graphics.stanford.edu/~seander/bithacks.html

with

http://aggregate.org/MAGIC/

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=386

http://www.sjbaker.org/steve/software/cute_code.html

http://www.ugcs.caltech.edu/~wnoise/base2.html

http://www.cit.gu.edu.au/~anthony/info/C/bit_programming.txt

also being good, and with

http://mandala.co.uk/java/bitutils/BitUtils.java

offering code examples in java.

bbatmana at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 3

well yes of course you use a 256 byte look up table if you have access to the XLAT instruction to coun't the bits. Everyone knows that! It's not like shifting and masking is free!

But I rather assumed that since you were here on a Java site asking questions about some disgusting high level interpreted language running on a virtual machine that you didn't really care THAT much about speed.

And by the way, don't mistake modesty for stupidity. Of course what I typed in was correct. I was just reminding you that you should always test code that you import from off the web.

Enjoy!

marlin314a at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 4

Yeah, table lookup is such an obvious thing to do that I should have thought of that myself--kinda embarassed that I didn't.

I don't have the time to do it now myself, but I am curious to see how the table lookup benchmarks against the best of the bit twiddling algorithms. My understanding is that cpu and caching are so critical that only benchmarking can determine what is best for a particular machine.

I also wonder if the latest JVMs are intelligent enough on x86 architectures to use the XLAT instruction that you mentioned for small tables like what this case would use.

Sorry that you seem to have got your feelings hurt from my last post--no offense was meant, you turned me on to some good stuff.

I thought that my original posting was clear that I wanted optimal performance.

Do you have any good references proving that Java is so bad on performance for applications like this?

The only related study that I can think of is the extensive numerical/scientific benchmarking done here:

http://www.shudo.net/jit/perf/

That guy found that Java compares quite decently with C/C++.

bbatmana at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 5

no offence taken.

I have no data on perfromance of the JVM. Having spent my early life writing code in assembly for space/speed/performance reasons I now take delight in never working on problems where perfromance is an issue. It is nice to be bilssfully free of such concerns.

If you are concerned with speed you will need to eventually profile. If and when you do, I predict that you would find that the look up table will be just a tad slower than the code I supplied.

I think that speeds will be so close that it won't much matter, but I would guess that the address calculations for the lookup table and the cache performance will end up eliminating the advantage of doing basically 4 arithmetic calculations in the table look up vs the 5 in the code I supplied.

If you do implement both, and run them in a timed trial, do post the results back here so that we may all know who gets the gold and who gets the silver.

marlin314a at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 6

To followup: I just discovered, while looking for something else, that Sun added several bit logic methods to the Integer and Long classes for Java 1.5.

I would never have posted this in the first place had I known that those methods existed...

marlin314: it looks like they used essentially the same code as you originally posted; from the Integer class:

/**

* Returns the number of one-bits in the two's complement binary

* representation of the specified <tt>int</tt> value. This function is

* sometimes referred to as the <i>population count</i>.

*

* @return the number of one-bits in the two's complement binary

*representation of the specified <tt>int</tt> value.

* @since 1.5

*/

public static int bitCount(int i) {

// HD, Figure 5-2

i = i - ((i >>> 1) & 0x55555555);

i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);

i = (i + (i >>> 4)) & 0x0f0f0f0f;

i = i + (i >>> 8);

i = i + (i >>> 16);

return i & 0x3f;

}

bbatmana at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 7
thanks for the post. I never upgraded from 1.4 so I didn't notice.
marlin314a at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...
# 8
I've come to really love 1.5--one of sun's best releases.Lots of goodies, but the concurrency package, generics, vastly better jvm monitoring (especially programmatic deadlock detection) are among stuff that I absolutely cannot live without now. I could never go back to 1.4.
bbatmana at 2007-7-13 11:28:42 > top of Java-index,Other Topics,Algorithms...