我有一个大号的标准库容器,如果我将它们加在一起就会导致溢出。让我们假装它是这个容器:
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
?
答案 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)
可以进一步改进。