23

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

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

4

5 回答 5

25

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

传递给函数的返回类型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;
}
于 2015-04-16T20:14:54.130 回答
8

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

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

这利用了新的 C++14 特性,初始化捕获,将状态存储在 lambda 中。(你可以通过捕获一个额外的局部变量来做同样的事情,但它的作用域是局部作用域,而不是 lambda 的生命周期。)对于旧的 C++ 版本,你自然可以将counta 的成员变量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;
};
于 2015-04-16T20:30:11.927 回答
1

您运行的“平均值”是 lambda 的第一个参数,因此以下是正确的。

lambda = [&](int a, int b){return a + b/v.size();};
于 2015-04-16T20:12:08.117 回答
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 函数时都不需要将“a”除以 v.size()。

针对上述情况得出正确的 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;
    }

PS : 'iota' 用于以递增方式初始化一个范围,这里它初始化向量从 1 到 10

于 2019-07-23T14:30:21.443 回答
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)

于 2021-03-26T23:36:21.247 回答