Here we test the 3 bit counting methods. We run each in a tight loop. Because the performance results are so clear, we do not need to worry about the ordering of the tests.
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
InitializeBitcounts();
const int m = 100000000;
Stopwatch s1 = Stopwatch.StartNew();
// Version 1: use sparse.
for (int i = 0; i < m; i++)
{
SparseBitcount(i);
}
s1.Stop();
Stopwatch s2 = Stopwatch.StartNew();
// Version 2: use iterated.
for (int i = 0; i < m; i++)
{
IteratedBitcount(i);
}
s2.Stop();
Stopwatch s3 = Stopwatch.StartNew();
// Version 3: use precomputed.
for (int i = 0; i < m; i++)
{
PrecomputedBitcount(i);
}
s3.Stop();
Console.WriteLine(
"{0}\n{1}\n{2}", s1.ElapsedMilliseconds, s2.ElapsedMilliseconds, s3.ElapsedMilliseconds);
}
static int SparseBitcount(int n)
{
int count = 0;
while (n != 0)
{
count++;
n &= (n - 1);
}
return count;
}
static int IteratedBitcount(int n)
{
int test = n;
int count = 0;
while (test != 0)
{
if ((test & 1) == 1)
{
count++;
}
test >>= 1;
}
return count;
}
static int[] _bitcounts;
static void InitializeBitcounts()
{
_bitcounts = new int[65536];
int position1 = -1;
int position2 = -1;
for (int i = 1; i < 65536; i++, position1++)
{
if (position1 == position2)
{
position1 = 0;
position2 = i;
}
_bitcounts[i] = _bitcounts[position1] + 1;
}
}
static int PrecomputedBitcount(int value)
{
return _bitcounts[value & 65535] + _bitcounts[(value >> 16) & 65535];
}
}
704 ms Sparse bit count
5198 ms Iterated bit count
199 ms Precomputed bit count