两个大的稀疏向量上的按位运算符而不循环?

时间:2019-06-18 19:50:47

标签: c++ std

我有三个大的任意稀疏布尔向量,它们的大小都相同-说:pool1pool2intersection_of_other_pools。我对执行按位运算符感兴趣。如果可以,那就太好了:intersection_of_other_pools |= pool1 | pool2,但就我所能发现的那样,这似乎不是一个选择。

由于所有这些向量的大小都非常大,并且pool1pool2都很稀疏,因此我想对一种在没有向量的情况下对这些向量执行按位运算的方法感兴趣循环。我知道std::vector<bool>的幕后实现只是一个位数组,这使我相信无需循环就可以做到这一点。

我愿意以速度的名义接受奇怪的按位破解解决方案。

当然,如果最快的方法(或唯一的方法)只是循环,那么我也会很乐意接受它作为答案。

我已经检查出valarray作为向量的潜在替代者,但是我无法确定它是循环的还是正在执行一些神奇的按位运算。但理想情况下,我不想更改现有的代码库。

2 个答案:

答案 0 :(得分:2)

实现为std::vector<uint64_t>时,您的CPU可能会非常快地对它们执行按位“或”运算。它们将与内存对齐,因此便于缓存。 循环并没有您想像的那么糟糕,因为在不同的数据结构上总会有一个隐藏的隐式循环。

如果其极稀疏(<< 1的千分之一),则只需将“集合”位的索引存储在(排序的)向量中,然后使用std::set_intersection进行匹配

答案 1 :(得分:2)

对于稀疏数组,请勿使用std::vector<bool>或类似名称。

真正稀疏的数组应该可以跳过较大的部分。

将您的数据编码为块标题,该标题说明该区域以字节为单位的长度。用长度中的所有1递归地表示“长度字段的长度是其长度的两倍并遵循”。

因此0xFF0100声明后面跟随着一个长度为512的块。 (您可以通过不允许0或1-254来做得更好,但这是舍入误差)。

“全0”的备用块与1和0混合的块。

不要直接读取块头;使用memcpy进入对齐的存储。

一旦有了此操作,您的|&操作就比按位操作更多。只有在极少数情况下,两者都有一个非零的块,您才真正进行按位运算。

完成&之后,您可能要检查是否有任何非0区域实际上都是0。

这假定为极为稀疏的位域。例如,每10000个位中设置1位是典型情况。如果稀疏的意思是“十分之一”,则只需使用uint64_t之类的向量即可。