EMB*_*LEM 19 c++ lambda accumulate
我有一个大数字的标准库容器,如果我将它们加在一起它们可能会导致溢出.让我们假装它是这个容器:
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Run Code Online (Sandbox Code Playgroud)
我想用std :: accumulate来计算这个容器的平均值,但我不能将所有数字加在一起.我只是计算它v[0]/v.size() + v[1]/v.size() + ....所以我设置:
auto lambda = ...;
std::cout << std::accumulate(v.begin(), v.end(), 0, lambda) << std::endl;
Run Code Online (Sandbox Code Playgroud)
这是我到目前为止所尝试的,其中->表示输出:
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
Run Code Online (Sandbox Code Playgroud)
我怎样才能产生正确的平均值,以便输出5?
Ada*_*amF 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;
}
Run Code Online (Sandbox Code Playgroud)
这可能不会很好地圆,但即使size()容器上没有方法,它也可以工作:
auto lambda = [count = 0](double a, int b) mutable { return a + (b-a)/++count; };
Run Code Online (Sandbox Code Playgroud)
这利用了新的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;
};
Run Code Online (Sandbox Code Playgroud)