如何在卷积程序的 c++ 中优化嵌套循环

How to optimize nested loop in c++ for a convolution program

本文关键字:c++ 优化 嵌套循环 程序 卷积      更新时间:2023-10-16

我是新手,我有一个卷积程序,可以接收一个数据文件,卷积它并输出另一个文件。我在这里附加代码。

void convolute()
{
ifstream fin;
ofstream fout;
int count = 0;
double a=0,b=0;
string input_file_string = "maxclus_500000node_3M_5000ens_666.dat";
string output_file_string = "1convolute_"+input_file_string;
fin.open(input_file_string.c_str());
while(fin) //to know the size of array to initialize
{
fin>>a>>b;
count++;
}
fin.close();
double* c = NULL;
c = new double[count+1];
double* d = NULL;
d = new double[count+1];
for(int i=0;i<count+1;i++)
{
c[i] = 0;
d[i] = 0;
}
fin.open(input_file_string.c_str());
int n = 1;
while(fin) //takes in data
{
fin>>a>>b;
c[n] = a;
d[n] = b;
n++;
}
fin.close();
double* binom = NULL;
binom = new double[count];
double* summ = NULL;
summ = new double[count+1];
for(int i=0;i<count+1;i++) summ[i] = 0;
for(int i=0;i<count;i++) binom[i] = 0;
for(int j=1;j<count;++j) //main convolution of data takes place
{
int x,y;
double prob = j*1.0/(count-1);
binom[j] = 1;
for(int i=j+1;i<count;++i)
binom[i] = binom[i-1]*((count-1)-i+1)*1.0/i*prob/(1-prob);
for(int i=j-1;i>=0;--i)
binom[i] = binom[i+1]*(i+1)*1.0/((count-1)-i)*(1-prob)/prob;
double sum = 0;
for(int i=0;i<count;++i) sum += binom[i];
for(int i=0;i<count;++i) binom[i] /= sum;
sum = 0;
for(int i=1;i<count;++i) sum += d[i]*binom[i];
summ[j] = sum;
//fout<<c[j]<<'t'<<sum<<endl;
if(j%1000==0)
cout<<count-1<<'t'<<j<<endl;
}
cout<<"writing to file "<<endl;
fout.open(output_file_string.c_str());
for(int i=1;i<count;i++) fout<<c[i]<<'t'<<summ[i]<<endl;
fout.close();
delete [] c;
c = NULL;
delete [] d;
d = NULL;
delete [] binom;
binom = NULL;
delete [] summ;
summ = NULL;
}

我想知道,我能做些什么来加速主卷积发生的部分,我的数据文件非常大,需要很长时间才能完成。需要帮助。

由于嵌套的 for 循环,只有执行卷积的代码部分的运行时间为 T(n( = 5n2+ ....对于 n 较大的文件,这显然是相当低效的。

要解决此问题,您需要减少只有一行代码的 for 循环的数量。如果遍历整个数组,请在一次传递中执行尽可能多的操作。为了优化这一点,您需要重新构建执行逻辑的方式,以便尽可能少地使用 for 循环。

是否需要使用数组?向量将起到相同(且更有效(的目的,因为您可以在文件中读取时添加元素(而不必打开文件来获取计数......因此反过来,

vector.size();

为您提供矢量的大小。此外,仅当您要递增元素时才需要使用整个循环将数组初始化为 0。如果只是分配元素,则将数组初始化为 0 没有任何用处。

如果所有这些都在一个函数中,那么你真的需要拆分它。这个函数整体上是糟糕的风格,因为有许多不必要的操作,大量的for循环,函数太长,并且本身做太多超出卷积输入范围的事情。

#include <vector>
#include <fstream>
void convolute(/*data you need*/);
int main() {
string input_file_string = "maxclus_500000node_3M_5000ens_666.dat";
string output_file_string = "1convolute_"+input_file_string;
ifstream fin (input_file_string);
ofstream fout (output_file_string);
int count = 0;
double a=0,b=0;
vector<double> c;
vector<double> d;
while (fin >> a >> b) {
c.push_back(a);
d.push_back(d);
}
fin.close();
vector<double> binom;
vector<double> summ;
convolute(/*Pass the Data you need*/);
...
}

看看这有多简单?使用正确的数据类型可以大大简化您的生活。此外,为了可读性,请将操作放在下一行的 for 循环中。这使得更明显的是那里发生了一些事情,并且您仍然不需要使用括号(只要代码只有一行长(。

我试图删除你们中的一些循环。 请随时询问我的评论是否还不够。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <tuple>
#include <algorithm>
using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;
using std::pair;
void convolute()
{
string input_file_string = "maxclus_500000node_3M_5000ens_666.dat";
string output_file_string = "1convolute_" + input_file_string;

double a = 0, b = 0;
vector<pair<double, double>> coordinates;
ifstream fin;
fin.open(input_file_string.c_str());
while (fin)
{
fin >> a >> b;
coordinates.push_back({ a,b });
}
fin.close();
static int count = (int)coordinates.size();
vector<double> binom(coordinates.size(), 0);
vector<double> summ(coordinates.size(), 0);
const double probMul = 1.0 / (coordinates.size() - 1); //Probability multiplicator
for (int j = 1; j< coordinates.size(); ++j) //main convolution of data takes place
{
const double prob = j*probMul;
binom[j] = 1;
double sum = binom[j];
double sum_x = binom[j] * coordinates[j].second; // <- (A/X) + (B/X) +... <=> (A+B+C+...)/X
for (int i = j + 1; i < count; ++i) //from j+1 to end
{
binom[i] = binom[i - 1] * ((count - 1) - i + 1)*1.0 / i*prob / (1 - prob);
sum += binom[i];
sum_x += binom[i] * coordinates[i].second;
}
for (int i = j - 1; i >= 0; --i)  //from j-1 to front
{
binom[i] = binom[i + 1] * (i + 1)*1.0 / ((count - 1) - i)*(1 - prob) / prob;
sum += binom[i];
sum_x += binom[i] * coordinates[i].second;
}
summ[j] = sum_x / sum;
if (j % 1000 == 0)
{
cout << count - 1 << 't' << j << endl;
}
}

cout << "writing to file " << endl;
ofstream fout;
fout.open(output_file_string.c_str());
for (int i = 1; i < count; i++)
{
fout << coordinates[i].first << 't' << summ[i] << endl;
}
fout.close();
}

我无法测试它 - 所以这取决于你。