![]() |
1
27
使用简单的暴力有时是好的。
我认为precalc会将单词的值全部移位,并将它们放在16整数中
所以你得到了这样一个数组(假设
所以基本上是这样的:
假设编译过程与编写过程大致相同,则此过程的时间成本为每个输入字16次检查。每输入一位,这就有一个
不需要查表;而是右移
|
![]() |
2
17
您可以首先使用包含256个条目的表来检查位流中的每个字节(如果它包含在您要查找的16位字中)。你的桌子
然后,您可以使用
由于256个表项中最多有8个不是零,因此平均而言,您只需仔细查看每个第32个位置。只有对于这个字节(加上前一个字节和后一个字节),您才能使用位操作或reinier建议的一些掩蔽技术来查看是否存在匹配。 代码假定您使用小的尾端字节顺序。字节中位的顺序也可能是一个问题(每个已经实现CRC32校验和的人都知道)。 |
![]() |
3
10
alt text http://img70.imageshack.us/img70/8711/80541519.jpg 在这里,在第一个样本中检查1到8,在下一个样本中检查9到16,依此类推。现在当我们正在寻找一个 图案 ,我们将找到本协议的所有8种可能的安排(如下所示) 图案 正在初始化查找表:
让我们举个例子
安排的中间部分是
搜索模式: 计数 如下所示: 左边 是左查找表, 是中间查找表和 正当 是右查找表。
计数 图案 我可以给出一些经过测试的示例代码。
搜索模式: 数据 左边 中间的 是中间查找表和 正当 是右查找表。
限制: 图案 如果它被放置在流缓冲区的最末端。以下代码需要在循环后添加以克服此限制。
优点: 这个算法只需要 N-1 找到目标的逻辑步骤 图案 N |
![]() |
4
9
我有钱 Knuth-Morris-Pratt 带有两个字符的字母表。 |
![]() |
5
7
我将实现一个具有16个状态的状态机。 每个状态表示有多少接收位符合模式。如果下一个接收的位与模式的下一位一致,则机器进入下一个状态。如果情况并非如此,则机器返回到第一个状态(或者,如果模式的开头可以与较小数量的接收位匹配,则返回到另一个状态)。
|
![]() |
6
4
原子小鼠 看起来不错,直到我考虑了Luke和MSalter关于详细信息的要求。 事实证明,这些细节可能表明一种比KMP更快的方法。KMP文章链接到 对于搜索模式为“AAAAA”的特定情况。对于多模式搜索 可能最合适。 您可以找到进一步的介绍性讨论 here . |
![]() |
7
3
|
![]() |
8
3
我要做的是创建16个前缀和16个后缀。然后为每个16位输入块确定最长后缀匹配。如果下一个块的前缀匹配长度,那么就得到了一个匹配
后缀匹配实际上不需要16个比较。但是,这需要根据模式字进行预计算。例如,如果patternword是101010101010101010,则可以首先测试16位输入块的最后一位。如果该位为0,则只需测试…10101010即可。如果最后一位是1,则需要测试…1010101是否足够。每个都有8个,总共1+8个比较。如果patternword是1111110000,您仍然需要测试输入的最后一位是否匹配后缀。如果该位为1,则必须进行12个后缀匹配(regex:1{1,12}),但如果为0,则只有4个可能的匹配(regex 1111 1111 1111 0{1,4}),同样平均进行9次测试。添加
|
![]() |
9
3
|
![]() |
10
3
任何 O(n logn)时间内的位模式。计算位掩码与输入的互相关。大小分别为n和n'的序列x和掩模y的互相关定义如下:
然后出现与掩码完全匹配的位模式,其中R(m)=Y,其中Y是位掩码中的位模式之和。 因此,如果您试图匹配位模式
那你必须用面具
可以在O(n logn)时间内使用FFT实现互相关。
|
![]() |
11
3
一种更简单的实现方法
@Toad's simple brute-force algorithm that checks every bit-position
是将数据移动到位,而不是移动掩码。不需要任何数组,只需右移就可以了
(在多个问题中,我注意到创建一个掩码的效率往往低于仅仅移出不需要的位。)
(正确处理
这相当重要 更多 对于大多数ISA(如x86、AARC64和ARM),从具有最新gcc和clang的阵列加载掩码的效率要高于从阵列加载掩码的效率。
编译器将循环完全展开16倍,因此可以将位字段提取指令与立即操作数(如ARM)一起使用
在x86上,CPU可以进行忽略高位的16位比较,例如。
某些ISA的一些编译器在@Toad版本上的工作与此一样出色,例如,PowerPC的clang使用
AVX2蛮力有(至少)两种方法可以做到这一点:
使用64位元素移位而不是32位,我们可以检查多个相邻的16位窗口,而不是总是忽略上16位(其中零被移入)。但我们仍然在SIMD元素边界处有一个中断,零被移入,而不是来自更高地址的实际数据。(未来的解决方案:AVX512VBMI2双移位
也许这样做是值得的,然后再来看看我们在一个数组中每个64位元素顶部遗漏的4x 16位元素
这对于通常很快找到命中的搜索非常有用,尤其是在少于前32字节的数据中。这对于大型搜索来说并不坏(但仍然是纯粹的暴力,一次只检查一个单词),在Skylake上可能并不比并行检查多个窗口的16个偏移量差。 这是对SkyLink的调整,在其他CPU上,变量移位效率较低,你可能只考虑偏移量为1…7的7个变量移位,然后通过移位来创建偏移量8。15。或者完全是别的什么。
with gcc/clang
(on Godbolt)
,具有直接从内存进行广播的内部循环。(优化
导栓连杆上还包括一个测试
这是8 uops的工作量+3 uops的循环开销(假设and/jne和cmp/jb的宏融合,我们将在Haswell/Skylake上得到)。在AMD上,256位指令是多个UOP,这将更加复杂。 当然,也可以使用纯右移立即将所有元素移动1,然后 并行检查多个窗口 而不是同一窗口中的多个偏移。 没有有效的可变移位(尤其是根本没有AVX2) ,这对于大型搜索来说会更好,即使它需要更多的工作来确定第一次点击的位置,以防出现 是 成功。(在找到最低元素以外的某个命中后,需要检查所有早期窗口的所有剩余偏移。) |
![]() |
12
2
也许你应该在一个向量(vec_str)中流入你的比特流,在另一个向量(vec_pattern)中流入你的模式,然后像下面的算法那样做
(希望算法正确) |
![]() |
13
1
这个循环的主循环有18条指令长,每次迭代处理2个字节。如果安装成本不是一个问题,那么这应该是最快的。 |
![]() |
Community wiki · C中有哪些耗时的操作? 1 年前 |
![]() |
Community wiki · 将所有处理器电源都投入到任务中 1 年前 |
![]() |
Community wiki · C++为C添加了什么?[已关闭] 1 年前 |
![]() |
Community wiki · 打印1到1000,不带循环或条件 1 年前 |