如何使用 std::accumulate 和 lambda 计算平均值?
How can I use std::accumulate and a lambda to calculate a mean?
我有一个包含大量数字的标准库容器,大到如果我将它们加在一起可能会导致溢出。让我们假设它是这个容器:
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
?
您的 运行 "average" 是 lambda 的第一个参数,因此以下是正确的。
lambda = [&](int a, int b){return a + b/v.size();};
您不应该使用整数来存储结果:
传递给函数的return类型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;
}
这可能不太圆润,但即使在容器上没有 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;
};
您使用的三个 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 在 time.For 的给定点处携带向量的特定索引的平均值,实例 'a' 的值当 'b' 的值为 1 时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;
}
P.S : 'iota'用于以递增的方式初始化一个范围,这里它初始化向量从1到10
我还没有看到这个不需要传递向量大小的解决方案
因为已经用 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)
可以进一步改进。
我有一个包含大量数字的标准库容器,大到如果我将它们加在一起可能会导致溢出。让我们假设它是这个容器:
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
?
您的 运行 "average" 是 lambda 的第一个参数,因此以下是正确的。
lambda = [&](int a, int b){return a + b/v.size();};
您不应该使用整数来存储结果:
传递给函数的return类型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;
}
这可能不太圆润,但即使在容器上没有 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;
};
您使用的三个 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 在 time.For 的给定点处携带向量的特定索引的平均值,实例 'a' 的值当 'b' 的值为 1 时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;
}
P.S : 'iota'用于以递增的方式初始化一个范围,这里它初始化向量从1到10
我还没有看到这个不需要传递向量大小的解决方案
因为已经用 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)
可以进一步改进。