我需要比较两个数字,并在更重要的位中寻找相似之处。我正在尝试确定不同的最低有效位数。
10111000
10111011
184和187要求偏移量为2,因为只有两个最低有效位不同。
10111011
11111011
187和251要求偏移量为7,因为第七个最低有效位不同。
我的第一个想法是将数字异或,然后向右移位直到数字等于零。我觉得有一个更好的逐位解决方案,这不涉及循环,但我没有做足够的自我努力来提出它。
解决方案需要适用于任何64位,因为我的数字存储为UInt64
。这是用C#编写的,但解决方案很可能是与语言无关的解决方案。
11101101
11010101
需要6位的偏移量。我试图找出有多少相似的位,我可以脱颖而出。
答案 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。