如何确定相似位数?

时间:2010-09-26 17:13:09

标签: algorithm bit-manipulation

我需要比较两个数字,并在更重要的位中寻找相似之处。我正在尝试确定不同的最低有效位数。

10111000
10111011

184和187要求偏移量为2,因为只有两个最低有效位不同。

10111011
11111011

187和251要求偏移量为7,因为第七个最低有效位不同。

我的第一个想法是将数字异或,然后向右移位直到数字等于零。我觉得有一个更好的逐位解决方案,这不涉及循环,但我没有做足够的自我努力来提出它。

解决方案需要适用于任何64位,因为我的数字存储为UInt64。这是用C#编写的,但解决方案很可能是与语言无关的解决方案。


11101101
11010101

需要6位的偏移量。我试图找出有多少相似的位,我可以脱颖而出。

5 个答案:

答案 0 :(得分:1)

听起来你已经发现了主要的伎俩; r = x XOR y,然后找到r中的最高位。有许多不同的方法来解决that problem here。通过将r分成两半并检查上半部分是否为零,在O(n)操作中最快。如果你在固定的位数(你说64)上这样做,那么展开循环以获得一系列测试:

pos = 0
r = x XOR y
if r>>32 == 0 :
   r = r & 2^32-1
else
   pos += 32
   r = r>>32
if r>>16 == 0 :
   r = r & 2^16-1
else
   pos += 16
   r = r>16
... etc

答案 1 :(得分:1)

#include <stdio.h>
#include <stdlib.h>

#define TO_L(s) (strtol((s), NULL, 16))

int tsb(unsigned long xa, unsigned long xb) {
  unsigned long v = xa ^ xb;
  static const unsigned long b[] = {
    0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000L, 0xFFFFffff00000000L
  };
  static const unsigned int S[]  = { 1, 2, 4, 8, 16, 32 };
  unsigned int r = 0;

#define STEP(i)   \
  if(v & b[i]) {  \
    int t = S[i]; \
    v >>= t;      \
    r  |= t;      \
  }
  STEP(5)
  STEP(4)
  STEP(3)
  STEP(2)
  STEP(1)
  STEP(0)
  return r;
}

int main(int ac, char **av) {
  return printf("%d\n", tsb(TO_L(av[1]), TO_L(av[2]))), 0;
}

我认为这可以实现您的算法,而且速度非常快,只需要6个步骤。请参阅此 great source of bit twiddling hacks

so ross$ ./a.out 1f f
4
so ross$ ./a.out 471234abcdabcd 981234abcdabcd
55
so ross$ ./a.out 1deadbeef 7feedface
34

答案 2 :(得分:0)

这样的东西
floor( log(184 ^ 187) / log(2) ) + 1

没有循环,但可能不会更快,因为登录成本高昂的操作。你应该对它进行测试,并与具有位移的简单循环进行比较。

有时一个(编码良好的)循环比无循环更快,特别是如果你有最多64次迭代而且往往更少。

<小时/> 更高效的代码版本:

预先计算

double Ilog2 = 1 / log(2);

然后每次你需要它

floor( log(184 ^ 187) * ILog2 ) + 1

答案 3 :(得分:0)

您可以编写一个O(log(n))循环来轻松找到最高设置位:

int findHighestSetBit(unsigned long long x) {
    int rv = 0;
    if (x == 0)
        return -1;  // no set bits
    for (int shift = 32; shift > 0; shift >>= 1) {
        if (x >> shift) {
            rv += shift;
            x >>= shift;
        }
    }
    return rv+1; // number least significant bit as '1' rather than '0'
}

如果速度太慢,您可以手动展开循环5次。

答案 4 :(得分:0)

首先假设您必须为8位数字执行此操作。 最快的方法是使用预编译值的256字节查找表:

static unsigned char highest_bit_num_LUT[256] = {0, 1, 2, 2, 3, etc }; // precomputed

unsigned diff = (unsigned)a ^ (unsigned)b; // sure you need XOR and not MINUS?
unsigned highest_bit_num = highest_bit_num_LUT[diff & 0xff];

现在扩展它以获得更高的位数:

static unsigned char highest_bit_num_LUT[256] = {0, 1, 2, 2, 3, etc }; // precomputed
unsigned diff = (unsigned)a ^ (unsigned)b; // sure you need XOR and not MINUS?
unsigned highest_bit_num = 0;
for (int i = 7; i >= 0; i--)    
    if (diff >> ( i*8) ){ // found most significant non-zero byte
        highest_bit_num = i*8 + highest_bit_num_LUT[diff >> (i*8)];
        break;
    }

所以现在我们最多有8次迭代。

编辑:在前3次迭代中使用DigitalRoss的想法会更快,然后使用LUT。