I am calculating the mean and standard deviation of the elements of a vector. I have two versions of this and I am completely puzzled why the version using the standard algorithms is slower than the one using plain loops.
Both version use this struct as return type:
struct MeanAndSigma {
double mean;
double sigma;
};
And the version with loops is this:
MeanAndSigma getMeanAndSigma(const DVector& v){
MeanAndSigma ms;
ms.mean = 0;
for (int i=0;i<v.size();++i){ms.mean += v[i];}
ms.mean = ms.mean / v.size();
double sqsum = 0;
for (int i=0;i<v.size();++i){sqsum += (v[i]-ms.mean)*(v[i]-ms.mean);}
ms.sigma = std::sqrt(sqsum / (v.size()-1));
return ms;
}
And the one with algorithms:
MeanAndSigma getMeanAndSigma2(const DVector& v){
MeanAndSigma ms;
ms.mean = std::accumulate(v.begin(),v.end(),0.0) / v.size();
DVector diff(v.size());
std::transform(v.begin(),v.end(),diff.begin(),
std::bind2nd(std::minus<double>(), ms.mean));
double sqsum = std::inner_product(diff.begin(),diff.end(),diff.begin(),0.0);
ms.sigma = std::sqrt(sqsum / (v.size()-1));
return ms;
}
When I measure the time they take per 10k calls with a vector with 10k elements I get ~2.0 seconds for the version with loops and ~3.2 seconds for the one with algorithms. Why is this?
I already compared cpu time and real time, but it seems as if both are running (as expected) on a single cpu. Am I doing something stupidly wrong in using the algorithms?
EDIT: I am not claiming, that the two versions are equivalent. Nevertheless I would have expected that the second version would be faster. As pointed out in comments and an answer, the second version uses an extra iteration over the elements and an extra DVector
(which is btw just a typedef std::vector<double>
). However, I am not familiar enough with the standard algorithms to improve the second version. So, now my question is:
How can I improve the version with algorithms to be faster than the one using plain loops?
I don't think the programs are equivalent. In the second version (using algorithms) a new vector of doubles is being populated and an extra iteration is also involved.
You could try this (c++11 version), it is equivalent of the first version. I haven't tried running it, it should work with some minor changes.
MeanAndSigma getMeanAndSigma2(const DVector& v){
MeanAndSigma ms;
ms.mean = std::accumulate(v.begin(),v.end(),0.0) / v.size();
double sqsum = std::accumulate(v.begin(),v.end(),
[ms](double sum, double ve){ return sum + (ve-ms.mean)*(ve-ms.mean);}
);
ms.sigma = std::sqrt(sqsum / (v.size()-1));
return ms;
}
Without lambdas (not tested, might need some minor changes)
class DiffSquare
{
public:
DiffSquare(double m) : _m(m) {}
double operator()(double sum, double e)
{
return sum + (e - _m) * (e - _m);
}
private:
double _m;
};
MeanAndSigma getMeanAndSigma2(const DVector& v) {
MeanAndSigma ms;
ms.mean = std::accumulate(v.begin(),v.end(),0.0) / v.size();
DiffSquare diff_square(ms.mean);
double sqsum = std::accumulate(v.begin(),v.end(),
0.0,
diff_square
);
ms.sigma = std::sqrt(sqsum / (v.size()-1));
return ms;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With