一尘不染

扫描位流中最快的位模式的方法

algorithm

我需要在位流中扫描16位字。 不保证在字节或字边界上对齐

实现此目标的最快方法是什么?暴力破解方法有很多种。使用表和/或移位,但是是否有任何“位旋转快捷方式”可以通过给出yes / no
/也许包含每个字节或单词到达时的标志结果来减少计算量?

C代码,内在函数,x86机器代码都会很有趣。


阅读 214

收藏
2020-07-28

共1个答案

一尘不染

使用简单的暴力有时是好的。

我认为预先计算该单词的所有移位值并将它们放入16个整数中,这样就得到了一个这样的数组(假设int宽度是的两倍short

 unsigned short pattern = 1234;
 unsigned int preShifts[16];
 unsigned int masks[16];
 int i;
 for(i=0; i<16; i++)
 {
      preShifts[i] = (unsigned int)(pattern<<i);  //gets promoted to int
      masks[i] = (unsigned int) (0xffff<<i);
 }

然后,对于每一个无符号的空位,请从流中取出一个整数,并将该空位和前一个空位作一个整数,并将该无符号的整数与16个无符号的整数进行比较。如果其中任何一个匹配,您就得到了一个。

所以基本上是这样的:

  int numMatch(unsigned short curWord, unsigned short prevWord)
  {
       int numHits = 0;
       int combinedWords = (prevWord<<16) + curWord;

       int i=0;
       for(i=0; i<16; i++)
       {
             if((combinedWords & masks[i]) == preShifsts[i]) numHits++;
       }
       return numHits;
  }

请注意,当在同一位上多次检测到模式时,这可能意味着多次命中:

例如32位0,而您要检测的模式是16 0,则意味着该模式被检测了16次!


假设它的编译时间大致与编写的时间相同,则每个输入字的时间成本为16个检查。对于每个输入位,这将执行&和和运算==,并进行分支或其他条件增量。并针对掩码的每一位进行表查找。

无需查找表;通过取而代之的是右移,combined我们可以获得效率显着提高的asm,如另一个答案所示,该答案还显示了如何在x86上使用SIMD将其向量化。

2020-07-28