假设大小为M的比特序列和大小为N的另一比特序列,其中M>> N. M和N都可以保存在整数数组中:如果N的长度为30,则需要一个只有一个整数的数组,但如果N的长度为300,那么将需要一个包含10个整数的数组来存储它。
我要做的是将N移到M内,并且对于M内的每个可能位置k,找到N和M(k)之间的差异数(通过异或)。如果M具有10000位且N具有100位,则存在10000-100 = 9900个位置,其中将执行XOR比较。
您是否知道可以执行此操作的库或可能提出算法?我知道它可以通过许多其他方式完成,但我相信最快的方法是这里提出的方法。如果你能想到一个更快的方式,那么我愿意接受建议!
我更喜欢C或C ++中的东西,但其他语言,甚至伪代码也是可以接受的。
提前致谢。
答案 0 :(得分:1)
简单方法:
while N < M * (original N) do
compute and tally up M xor N
multiply each word (unsigned) in N by 2, // i.e. shift left 1 bit
and add in the carry (= overflow) from the previous word.
现代CPU足够强大,即使是10,000和100位,这也只需要几毫秒。
要“计算和计算M xor N”,
sum = 0
for (i=0; i<M/8; i++)
if M[i] != 0
w = M[i]
while w != 0
if ((w & 1) != 0) sum++ // test LSB
w /= 2 // shift right 1 bit
有很多方法可以优化它。有很多数字在大多数情况下都是0,你可以识别并忽略这些......但上面的算法应该让你开始。
答案 1 :(得分:1)
这是一个完整且有效的解决方案。作为读者的练习,留下了轻微的邋。:)
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define M_SIZE 100
#define N_SIZE 25
#define bitsToBytes(n) ((n + 7)/8)
typedef unsigned char byte;
void dumpBytes(byte *arr, size_t size) {
int b;
for (b=0; b<size; b++) {
printf("%02x", *arr++);
}
printf("\n");
}
int main(int argc, char *argv[]) {
byte M[bitsToBytes(M_SIZE)], N[bitsToBytes(N_SIZE)];
/* Fill M and N with random bits */
int b;
for (b=0; b<sizeof(M); b++) {
M[b] = 0xff & rand();
}
for (b=0; b<sizeof(N); b++) {
N[b] = 0xff & rand();
}
/* Create a couple of arrays big enough for M_SIZE + N_SIZE,
to allow shifting N all the way before the left of M. */
#define MN_SIZE (M_SIZE + N_SIZE)
#define MN_BYTES (bitsToBytes(MN_SIZE))
byte MM[MN_BYTES], NN[MN_BYTES];
/* Zero out MM, NN, then copy M, N there (right justified). */
int offset = sizeof(MM) - sizeof(M);
memset (MM, 0, sizeof(MM)); memcpy(MM+offset, M, sizeof(M));
offset = sizeof(NN) - sizeof(N);
memset (NN, 0, sizeof(NN)); memcpy(NN+offset, N, sizeof(N));
dumpBytes(MM, MN_BYTES);
/* Count up "difference bits" until NN has been left-shifted into oblivion. */
int s;
for (s=0; s<MN_SIZE; s++) {
int sum = 0;
for (b=0; b<MN_BYTES; b++) {
int xor = MM[b] ^ NN[b];
while (xor != 0) {
sum += (xor & 1);
xor >>= 1;
}
}
dumpBytes(NN, MN_BYTES);
printf("Shift: %4d; bits: %3d.\n", s, sum);
/* shift NN one bit to the left */
for (b=0; b<MN_BYTES; b++) {
NN[b] <<= 1;
if (b < (MN_BYTES - 1) && ((NN[b+1] & 0x80) != 0)) NN[b] |= 1;
}
}
}
答案 2 :(得分:1)
你可以将N向上移动超过M或将M向下移动到N.当移动N时,如果输入与字大小不对齐,你还需要移动掩模。这些移位可以缓存到一个字长大小的数组中,但是如果每个字移位多个字是1个指令(如果你使用RCR指令),则可能不值得挽救L1缓存的风险。 / p>
除非您可以依靠带有POPCNT指令的Core i7处理器,否则最重要的部分将是位计数。有关位计数的快速实现,请参阅this page。
对于较小的N长度(在机器字中),通过内圈的特殊套管可以大大提高速度。对于具有SSE4.2的处理器上的N <= 192位,它应该能够运行两个最内层的循环并将所有内容保持在寄存器中。我生锈的ASM向我显示了14个实时寄存器,其中最内层循环(移位64位位置)长度为20条指令,另外5条用于读取输入中的下一个字。)