二进制序列的和减少

时间:2012-10-02 12:05:05

标签: algorithm parallel-processing

考虑二进制序列:

11000111

我必须找到这个系列的总和(实际上并行)

Sum = 1 + 1 + 0 + 0 + 0 + 1 + 1 + 1 = 5

这是浪费资源,为什么要投入时间来增加0?

有没有巧妙的方法来总结这个序列,以便我可以避免不必要的添加?

5 个答案:

答案 0 :(得分:3)

在字节级而不是位级操作。 Use a small LUT to convert a byte to a population count。这样你只需要进行一次查找,每8位进行一次添加。除非您的数据可能非常稀疏,否则这应该非常有效。

答案 1 :(得分:0)

这取决于你如何存储你的bitset。 如果它是一个数组,那么你不能做一个普通的。如果要并行执行此操作,只需将数组拆分并同时处理它们。

如果我们讨论的是bitset(以本机(32/64位)整数类型存储这些位),那么计算位的最简单方法就是这样:

int bitset;
int s = 0;
for (; bitset; s++)
    bitset &= bitset-1;

这会删除每一步的最后一位,所以你有O(s)。

当然,如果需要超过32/64位,可以将这两种方法结合使用

答案 2 :(得分:0)

我不知道为什么人们会回答,甚至没有考虑从第一条评论到问题的链接。您可以轻松地在O(size_of_bitset)下进行制作。至关重要的是,它涉及到恒定因素。

您可以使用此方法(由J.F.Sebastian在link中找到):

inline int count_bits(int num){
int sum = 0;
for (; bitset; sum++) bitset &= bitset-1;
return sum;
}

int main (void){
  int array[N];
  int total_sum = 0;
  #pragma omp parallel for reduction(+:total_sum)
  for (size_t i = 0; i < N, i++){
     total_sum += count_bits(array[i]);
  }
}

这将统计array内存范围内的位数。内联对于避免不必要的复制很重要,编译器也应该更好地优化它。

您可以将count_bits更换为更好的计算整数位的内容,以便在找到任何内容时更快。此版本的复杂度为O(bits_set)(不是位集的大小!)。

调用并行构造会引入相当多的开销,而单个求和则需要相当大的补偿。

并行性是通过OpenMP完成的。每个线程的部分和在并行循环的末尾求和并存储在total_sum中。请注意,由于reduction子句,total_sum在每个线程reduction的循环内都是私有的。

您可以更改代码以使其计数在任意内存区域中设置的位,但是当您在如此低的级别执行操作时,它与内存对齐非常重要。

答案 3 :(得分:-1)

将其视为字符串。您必须至少读取一次输入符号,因此您至少需要O(n)时间。

添加速度很快,只需一个周期。使用某种条件逻辑意味着不必要的分支 - 但如今编译器可能会优化它。

如果需要并行性,则拆分输入字符串并同时处理它们。这是一个令人尴尬的并行问题。

答案 4 :(得分:-1)

据我所知,尝试特别处理零会很浪费。正如@bdares所说,加入真的很便宜。至少,你需要执行N条指令来总结一个N位序列,如果你无条件地总和那么就是这样。如果添加测试以查看该位是0还是1,那么这是需要为每个位执行的另一条指令。即使没有分支惩罚,你每个位执行最小1条指令(条件测试),然后你也为任何等于1的位执行原始指令(add)。所以即使没有分支惩罚,这需要更多的时间来执行。

@bdares提到编译器会优化分支,但只有在编译时知道每个位的值,并且如果在编译时知道位的值,你应该自己添加它们提前。

可能有一些可爱的东西,你可以做点苦恼。例如,如果你一次取两个比特,你就要加上0,1,2或3的值,并且只有一半的加法要做。 可以通过某些东西然后你可以用结果将它转换成你想要的值,但我实际上并没有想过如何做到这一点。