我有以下代码来完成前缀和任务:
#include <iostream>
#include<math.h>
using namespace std;
int Log(int n){
int count=1;
while (n!=0){
n>>=1;
count++;
}
return count;
}
int main(){
int x[16]={39,21,20,50,13,18,2,33,49,39,47,15,30,47,24,1};
int n=sizeof(x)/sizeof(int );
for (int i=0;i<=(Log(n)-1);i++){
for (int j=0;j<=n-1;j++){
if (j>=(std::powf(2,i))){
int t=powf(2,i);
x[j]=x[j]+x[j-t];
}
}
}
for (int i=0;i<n;i++)
cout<<x[i]<< " ";
return 0;
}
来自this wikipedia page 但我错了结果有什么不对?请帮忙
答案 0 :(得分:6)
我不确定你的代码应该做什么,但实现前缀和实际上非常简单。例如,它使用任意操作计算迭代器范围的(独占)前缀和:
template <typename It, typename F, typename T>
inline void prescan(It front, It back, F op, T const& id) {
if (front == back) return;
typename iterator_traits<It>::value_type accu = *front;
*front++ = id;
for (; front != back; ++front) {
swap(*front, accu);
accu = op(accu, *front);
}
}
这遵循C ++标准库算法的界面风格。
要从代码中使用它,您可以编写以下内容:
prescan(x, x + n, std::plus<int>());
您是否尝试实施并行前缀和?这只有在您实际并行化代码时才有意义。按照目前的情况,你的代码是按顺序执行的,并且不会从你似乎采用的更复杂的鸿沟和征服逻辑中获得任何东西。
此外,您的代码确实存在错误。最重要的一个:
for(int i=0;i<=(Log(n)-1);i++)
在这里,你要迭代到floor(log(n)) - 1
。但是伪代码表明你实际上需要迭代到ceil(log(n)) - 1
。
此外,请考虑一下:
for (int j=0;j<=n-1;j++)
这不常见。通常,您可以编写如下代码:
for (int j = 0; j < n; ++j)
请注意,我使用<
代替<=
,并将界限从j - 1
调整为j
。对于外循环也是如此,所以你得到:
for (int i = 0; i < std::log(n); ++i)
最后,您可以使用std::powf
与pow(2, x)
相同的事实代替1 << x
(即利用操作库2作为位操作有效实现的事实)。这意味着你可以简单地写:
if (j >= 1 << i)
x[j] += x[j - (1 << i)];
答案 1 :(得分:4)
我认为std :: partial_sum会做你想要的 http://www.sgi.com/tech/stl/partial_sum.html
答案 2 :(得分:3)
让算法正常工作的最快方法:删除外部for(i...)
循环,而不是将i
设置为0,并仅使用内部for (j...)
循环。
int main(){
...
int i=0;
for (int j=0;j<=n-1;j++){
if (j>=(powf(2,i))){
int t=powf(2,i);
x[j]=x[j]+x[j-t];
}
}
...
}
或等效地:
for (int j=0; j<=n-1; j++) {
if (j>=1)
x[j] = x[j] + x[j-1];
}
...这是执行前缀和的直观方式,也可能是最快的非并行算法。
维基百科的算法旨在并行运行,这样所有的添加都完全相互独立。它读取所有值,添加到它们中,然后将它们全部并行地写回到数组中。在你的版本中,当你执行x [j] = x [j] + x [j-t]时,你正在使用你刚刚添加的x [j-t],t
迭代前。
如果你真的想要重现维基百科的算法,这是一种方法,但要注意它将比上面的直观方式慢得多,除非你使用的是并行编译器和带有一大堆处理器的计算机。
int main() {
int x[16]={39,21,20,50,13,18,2,33,49,39,47,15,30,47,24,1};
int y[16];
int n=sizeof(x)/sizeof(int);
for (int i=0;i<=(Log(n)-1);i++){
for (int j=0;j<=n-1;j++){
y[j] = x[j];
if (j>=(powf(2,i))){
int t=powf(2,i);
y[j] += x[j-t];
}
}
for (int j=0;j<=n-1;j++){
x[j] = y[j];
}
}
for (int i=0;i<n;i++)
cout<<x[i]<< " ";
cout<<endl;
}
附注:为了提高速度,您可以使用1<<i
代替powf(2,i)
。正如ergosys所提到的,你的Log()
功能需要工作;它返回的值太高,在这种情况下不会影响部分和的结果,但会花费更长的时间。