Question

Possible duplicate: Count number of bits in a 64-bit (long, big) integer?

For an image comparison algorithm I get a 64bit number as result. The amount of 1s in the number (ulong) (101011011100...) tells me how similar two images are, so I need to count them. How would I best do this in C#? I'd like to use this in a WinRT & Windows Phone App, so I'm also looking for a low-cost method.

EDIT: As I have to count the bits for a large number of Images, I'm wondering if the lookup-table-approach might be best. But I'm not really sure how that works...

Was it helpful?

Solution

The Sean Eron Anderson's Bit Twiddling Hacks has this trick, among others:

Counting bits set, in parallel

unsigned int v; // count bits set in this (32-bit value)
unsigned int c; // store the total here
static const int S[] = {1, 2, 4, 8, 16}; // Magic Binary Numbers
static const int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};

c = v - ((v >> 1) & B[0]);
c = ((c >> S[1]) & B[1]) + (c & B[1]);
c = ((c >> S[2]) + c) & B[2];
c = ((c >> S[3]) + c) & B[3];
c = ((c >> S[4]) + c) & B[4];

The B array, expressed as binary, is:

B[0] = 0x55555555 = 01010101 01010101 01010101 01010101
B[1] = 0x33333333 = 00110011 00110011 00110011 00110011
B[2] = 0x0F0F0F0F = 00001111 00001111 00001111 00001111
B[3] = 0x00FF00FF = 00000000 11111111 00000000 11111111
B[4] = 0x0000FFFF = 00000000 00000000 11111111 11111111

We can adjust the method for larger integer sizes by continuing with the patterns for the Binary Magic Numbers, B and S. If there are k bits, then we need the arrays S and B to be ceil(lg(k)) elements long, and we must compute the same number of expressions for c as S or B are long. For a 32-bit v, 16 operations are used. The best method for counting bits in a 32-bit integer v is the following:

v = v - ((v >> 1) & 0x55555555);                    // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);     // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count

The best bit counting method takes only 12 operations, which is the same as the lookup-table method, but avoids the memory and potential cache misses of a table. It is a hybrid between the purely parallel method above and the earlier methods using multiplies (in the section on counting bits with 64-bit instructions), though it doesn't use 64-bit instructions. The counts of bits set in the bytes is done in parallel, and the sum total of the bits set in the bytes is computed by multiplying by 0x1010101 and shifting right 24 bits.

A generalization of the best bit counting method to integers of bit-widths upto 128 (parameterized by type T) is this:

v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; // count

OTHER TIPS

Something along these lines would do (note that this isn't tested code, I just wrote it here, so it may and probably will require tweaking).

int numberOfOnes = 0;
for (int i = 63; i >= 0; i--)
{
    if ((yourUInt64 >> i) & 1 == 1) numberOfOnes++;
    else continue;
}

Option 1 - less iterations if 64bit result < 2^63:

byte numOfOnes;
while (result != 0)
{
    numOfOnes += (result & 0x1);
    result = (result >> 1);
}

return numOfOnes;

Option 2 - constant number of interations - can use loop unrolling:

byte NumOfOnes;

for (int i = 0; i < 64; i++)
{
    numOfOnes += (result & 0x1);
    result = (result >> 1);
}

this is a 32-bit version of BitCount, you could easily extend this to 64-bit version by add one more right shift by 32, and it would be very efficient.

int bitCount(int x) {
/* first let res = x&0xAAAAAAAA >> 1 + x&55555555
 * after that the (2k)th and (2k+1)th bits of the res
 * will be the number of 1s that contained by the (2k)th 
 * and (2k+1)th bits of x
 * we can use a similar way to caculate the number of 1s
 * that contained by the (4k)th and (4k+1)th and (4k+2)th 
 * and (4k+3)th bits of x, so as 8, 16, 32
 */ 
    int varA = (85 << 8) | 85;
    varA = (varA << 16) | varA;
    int res = ((x>>1) & varA) + (x & varA);

    varA = (51 << 8) | 51;
    varA = (varA << 16) | varA;
    res = ((res>>2) & varA) + (res & varA);

    varA = (15 << 8) | 15;
    varA = (varA << 16) | varA;
    res = ((res>>4) & varA) + (res & varA);

    varA = (255 << 16) | 255;
    res = ((res>>8) & varA) + (res & varA);

    varA = (255 << 8) | 255;
    res = ((res>>16) & varA) + (res & varA);
    return res;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top