对于图像比较算法,我得到64位数字作为结果。数量(ulong)(101011011100 ...)中的1的数量告诉我两个图像有多相似,所以我需要计算它们。我怎样才能在C#中做到最好? 我想在WinRT& Windows Phone App,所以我也在寻找一种低成本的方法。
编辑:因为我必须计算大量图像的位数,所以我想知道查找表方法是否最好。但我不确定它是如何运作的......
答案 0 :(得分:2)
Sean Eron Anderson's Bit Twiddling Hacks有这个伎俩,其中包括:
并行计数位
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];
表示为二进制的B数组是:
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
我们可以通过继续二进制幻数B,S的模式来调整更大整数的方法。如果有k位,那么我们需要数组S和B为ceil(lg(k))元素很长,我们必须为c计算相同数量的表达式,因为S或B很长。对于32位v,使用16个操作。 计算32位整数v中位的最佳方法如下:
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
最佳位计数方法仅执行12次操作,这与查找表方法相同,但避免了表的内存和潜在的高速缓存未命中。它是上面的纯粹并行方法和使用乘法的早期方法之间的混合(在使用64位指令计数位的部分中),尽管它不使用64位指令。字节中设置的位数是并行完成的,字节中设置的位总和是通过乘以0x1010101和右移24位来计算的。
将最佳位计数方法推广到位宽高达128的整数(由类型T参数化)是这样的:
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
答案 1 :(得分:1)
这些方面的东西会做(注意这不是经过测试的代码,我只是在这里写的,所以它可能并且可能需要调整)。
int numberOfOnes = 0;
for (int i = 63; i >= 0; i--)
{
if ((yourUInt64 >> i) & 1 == 1) numberOfOnes++;
else continue;
}
答案 2 :(得分:0)
这是一个32位版本的BitCount,您可以通过再添加一个右移32来轻松地将其扩展到64位版本,这将是非常有效的。
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;
}
答案 3 :(得分:0)
选项1 - 如果64位结果,则减少迭代次数< 2 ^ 63:
byte numOfOnes;
while (result != 0)
{
numOfOnes += (result & 0x1);
result = (result >> 1);
}
return numOfOnes;
选项2 - 常数交互 - 可以使用循环展开:
byte NumOfOnes;
for (int i = 0; i < 64; i++)
{
numOfOnes += (result & 0x1);
result = (result >> 1);
}