I have a standard library container of large numbers, so large that they may cause overflow if I add them together. Let's pretend it's this container:
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
I want to calculate the mean of this container, using std::accumulate, but I can't add all the numbers together. I'll just calculate it with v[0]/v.size() + v[1]/v.size() + ...
. So I set:
auto lambda = ...; std::cout << std::accumulate(v.begin(), v.end(), 0, lambda) << std::endl;
Here is what I have tried so far, where ->
indicates the output:
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
How can I produce the correct mean such that the output will be 5
?
std::accumulate() is a built-in function in C++'s Standard Template Library. The function takes in a beginning iterator, an ending iterator, initial value, and (by default) computes the sum of the given initial value and the elements in the given range. The function can also be used for left folding.
The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.
You shouldn't use integer to store the result:
The return type passed to the function accumulate:T accumulate( InputIt first, InputIt last, T init, BinaryOperation op );
depends on the third parameter type: (T init) so you have to put there: 0.0 to get result as 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; }
This may not round quite as nicely, but it works even when there's no size()
method on the container:
auto lambda = [count = 0](double a, int b) mutable { return a + (b-a)/++count; };
This takes advantage of a new C++14 features, initialized captures, to store state within the lambda. (You can do the same thing via capture of an extra local variable, but then its scope is local scope, rather than lifetime of the lambda.) For older C++ versions, you naturally can just put the count
in the member variable of a struct
and put the lambda body as its operator()()
implementation.
To prevent accumulation of rounding error (or at least dramatically reduce it), one can do something like:
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; };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With