Algorithm 二元序列的和归约

Algorithm 二元序列的和归约,algorithm,parallel-processing,Algorithm,Parallel Processing,考虑一个二进制序列: 11000111 我必须找到这个级数的和(实际上是并行的) 总和=1+1+0+0+0+1+1+1=5 这是对资源的浪费,为什么要花时间添加0 有没有什么聪明的方法可以对这个序列求和,这样我就可以避免不必要的加法 这取决于存储位集的方式。 如果它是一个数组,那么你不能为它做更多的简单操作。如果要并行执行此操作,只需将数组拆分为块并并行处理它们 如果我们讨论的是位集(以本机(32/64位)整数类型存储位),那么计算位的最简单方法是: int bitset; int s = 0;

考虑一个二进制序列:

11000111

我必须找到这个级数的和(实际上是并行的)

总和=1+1+0+0+0+1+1+1=5

这是对资源的浪费,为什么要花时间添加0


有没有什么聪明的方法可以对这个序列求和,这样我就可以避免不必要的加法

这取决于存储位集的方式。 如果它是一个数组,那么你不能为它做更多的简单操作。如果要并行执行此操作,只需将数组拆分为块并并行处理它们

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

int bitset;
int s = 0;
for (; bitset; s++)
    bitset &= bitset-1;
这将在每个步骤中删除最后一位1,因此您有O(s)


当然,如果您需要32/64位以上,您可以将这两种方法结合起来。这取决于您存储位集的方式。 如果它是一个数组,那么你不能为它做更多的简单操作。如果要并行执行此操作,只需将数组拆分为块并并行处理它们

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

int bitset;
int s = 0;
for (; bitset; s++)
    bitset &= bitset-1;
这将在每个步骤中删除最后一位1,因此您有O(s)


当然,如果您需要32/64位以上的数据,可以将这两种方法结合起来。据我所知,专门处理零是浪费时间的。正如@bdares所说,加法非常便宜。至少,您需要执行N条指令来对N位序列进行求和,如果您无条件地对任意一位求和的话。如果您添加一个测试来查看该位是0还是1,则需要为每个位执行另一条指令。即使没有分支惩罚,您也会对每一位执行至少1条指令(条件测试),然后对任何等于1的位执行原始指令(加法)。因此,即使没有分支惩罚,这也需要更多的时间来执行

@bdares提到编译器将优化分支,但这只是在编译时知道每个位的值的情况下,如果您在编译时知道这些位的值,那么您应该提前将它们相加


也许有一些可爱的事情,你可以做的一点旋转。例如,如果一次取两个位,则将0、1、2或3的值相加,只需要一半的加法。也许你可以对结果做些什么,把它转换成你想要的值,但我还没有真正考虑过怎么做。

据我所知,专门处理零是浪费时间的。正如@bdares所说,加法非常便宜。至少,您需要执行N条指令来对N位序列进行求和,如果您无条件地对任意一位求和的话。如果您添加一个测试来查看该位是0还是1,则需要为每个位执行另一条指令。即使没有分支惩罚,您也会对每一位执行至少1条指令(条件测试),然后对任何等于1的位执行原始指令(加法)。因此,即使没有分支惩罚,这也需要更多的时间来执行

@bdares提到编译器将优化分支,但这只是在编译时知道每个位的值的情况下,如果您在编译时知道这些位的值,那么您应该提前将它们相加


也许有一些可爱的事情,你可以做的一点旋转。例如,如果一次取两个位,则将0、1、2或3的值相加,只需要一半的加法。然后,您可以对结果执行某些操作,将其转换为所需的值,但我还没有真正考虑如何执行此操作。

在字节级别而不是位级别进行操作。这样,每8位只需执行一次查找和一次添加。除非您的数据可能非常稀疏,否则这应该是非常有效的。

在字节级别而不是位级别进行操作。这样,每8位只需执行一次查找和一次添加。除非你的数据可能非常稀少,否则这应该是相当有效的。

我不知道人们为什么要回答,甚至连从第一条评论到问题的链接都不看。您可以轻松地在
O(位集的大小)
下进行设置。至少在常数因子方面

您可以使用此方法(由J.F.Sebastian提供):

inline int count_位(int num){
整数和=0;
对于(;bitset;sum++)位集&=bitset-1;
回报金额;
}
内部主(空){
整数数组[N];
int total_sum=0;
#pragma omp并行减少(+:总和)
对于(大小i=0;i
这将并行计算
数组
的内存范围中的位数。内联对于避免不必要的复制很重要,而且编译器应该更好地优化它

您可以将
count_bits
与任何更好的整数位计数方法进行交换,以便在找到任何东西时更快。此版本的复杂性为
O(位集)
(不是位集的大小!)

与单个求和相比,调用并行构造将引入相当多的开销,需要相当大的开销才能补偿

并行性是通过OpenMP完成的。每个线程的部分和在并行循环结束时求和,并存储在
total\u sum
中。注意,由于reduction子句的缘故,
total_sum
在每个线程的循环内都是私有的


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

我不知道人们为什么要回答,甚至不看从第一条注释到问题的链接。你可以