我如何使用std :: accumulate和lambda来计算平均值?

时间:2015-04-16 20:08:42

标签: c++ lambda accumulate

我有一个大号的标准库容器,如果我将它们加在一起就会导致溢出。让我们假装它是这个容器:

std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

我想用std :: accumulate来计算这个容器的平均值,但我不能将所有数字加在一起。我将用v[0]/v.size() + v[1]/v.size() + ...计算它。所以我设置:

auto lambda = ...;
std::cout << std::accumulate(v.begin(), v.end(), 0, lambda) << std::endl;

以下是我到目前为止所尝试的内容,其中->表示输出:

lambda = [&](int a, int b){return (a + b)/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b;};  ->  10

如何生成正确的均值,使输出为5

5 个答案:

答案 0 :(得分:18)

您不应使用整数来存储结果:

传递给函数accumulate的返回类型:
T accumulate( InputIt first, InputIt last, T init, BinaryOperation op );取决于第三个参数类型:( T init )所以你必须放在那里:0.0将结果作为 double

#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
using namespace std;
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int main()
{
    auto lambda = [&](double a, double b){return a + b / v.size(); };
    std::cout << std::accumulate(v.begin(), v.end(), 0.0, lambda) << std::endl;
}

答案 1 :(得分:7)

这可能不太顺利,但即使容器上没有size()方法,它也能正常工作:

auto lambda = [count = 0](double a, int b) mutable { return a + (b-a)/++count; };

利用新的C ++ 14功能初始化捕获,在lambda中存储状态。 (你可以通过捕获额外的局部变量来做同样的事情,但是它的范围是局部范围,而不是lambda的生命周期。)对于较旧的C ++版本,你自然可以将count放在成员中struct的变量,并将lambda主体作为其operator()()实现。

为了防止累积误差累积(或至少大幅减少它),可以做类似的事情:

auto lambda = [count = 0, error = 0.0](double a, int b) mutable {
   const double desired_change = (b-a-error)/++count;
   const double newa = a + (desired_change + error);
   const double actual_change = newa - a;
   error += desired_change - actual_change;
   return newa;
};

答案 2 :(得分:1)

你的跑步&#34;平均&#34;是lambda的第一个参数,所以以下是正确的。

lambda = [&](int a, int b){return a + b/v.size();};

答案 3 :(得分:0)

您使用的三个lambda函数达不到要求。

lambda = [&](int a, int b){return (a + b)/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b;};  ->  10

这里使用的参数a在给定的时间点携带平均值直到向量的特定索引,例如,当'b'的值为1时'a'的值为0.0,当'b'变为2时那一刻应该是“ 0.1”。 那么很明显,在每次调用lambda函数时,都不需要用v.size()将'a'除掉。

针对上述情况使用正确的lambda函数

lambda = [&](double x,double y){return x+y/v.size();}

在这里我们引用引用只是因为我们需要v.size()的值,如果事先知道,向量的大小值就可以预先传递

工作程序是

    #include<iostream>
    #include<numeric>
    #include<vector>
    using namespace std;

    int main(){
        vector<int> v(10);
        iota(v.begin(),v.end(),1);
        double x=accumulate(v.begin(),v.end(),0.0,[&](double x,double y) {return x+y/v.size();});
        cout << x << endl;
    }

P.S:'iota'用于递增范围地初始化范围,此处将矢量从1初始化为10

答案 4 :(得分:0)

我还没有看到这个解决方案,它不介意传递向量的大小 因为已经用 v.begin(), v.end():

控制了范围
double mean = accumulate(v.begin(), v.end(), 0., [](double x, double y) { return x+y; }) / v.size();

v.size() 替换为 std::distance(start,end) 可以进一步改进。