std::accumulate not acting as expected
You need to pass a double
to accumulate
:
result = accumulate(vec.begin(), vec.end(), 0.0, sum);
^^^
otherwise the accumulation is performed using int
, and then converting the result to a double.
Why does std::accumulate generate 705032704 as output instead of the sum of the elements in the vector?
The standard algorithm std::accumulate
is declared the following way
template<class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init);
So the template parameter T
is used as the type of the accumulator.
In this call
std::accumulate(nums.begin(), nums.end(), 0)
the deduced type of the parameter T is int
because the integer literal 0
has the type int
. As a result there is an overflow of the sum stored in the accumulator of the type int
.
You have to use at least the long long integer literal 0ll
as
std::accumulate(nums.begin(), nums.end(), 0ll
)
or maybe it is reasonable to use a double floating literal
std::accumulate(nums.begin(), nums.end(), 0.0 )
Here is a demonstrative program
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>
using ll = long long int;
int main()
{
std::vector<ll> nums = {1000000000, 1000000000,1000000000,1000000000,1000000000};
std::cout << std::accumulate( std::begin( nums ), std::end( nums ), 0ll ) << '\n';
std::cout << std::accumulate( std::begin( nums ), std::end( nums ), 0.0 ) << '\n';
}
Its output is
5000000000
5e+09
Using accumulate to calculate alternate sum
This is my quick solution :
int sign = -1; // start with minus first (e.g. 1-2)
std::vector<int> values{ 1, 2, 3, 4, 5 };
auto value = std::accumulate(values.begin(), values.end(), 0, [&sign](int total, int value)
{
sign = -sign;
return total + (sign)*value;
});
Understanding std::accumulate
The way things are, it is annoying for code that knows for sure a range isn't empty and that wants to start accumulating from the first element of the range on. Depending on the operation that is used to accumulate with, it's not always obvious what the 'zero' value to use is.
If on the other hand you only provide a version that requires non-empty ranges, it's annoying for callers that don't know for sure that their ranges aren't empty. An additional burden is put on them.
One perspective is that the best of both worlds is of course to provide both functionality. As an example, Haskell provides both foldl1
and foldr1
(which require non-empty lists) alongside foldl
and foldr
(which mirror std::transform
).
Another perspective is that since the one can be implemented in terms of the other with a trivial transformation (as you've demonstrated: std::transform(std::next(b), e, *b, f)
-- std::next
is C++11 but the point still stands), it is preferable to make the interface as minimal as it can be with no real loss of expressive power.
std::reduce seems to convert results to integers
The version of std::reduce()
that you are calling:
template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOp>
T reduce(ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init, BinaryOp binary_op);
You can clearly see that the return value uses the same data type as the init
parameter, which in your case is being deduced as an int
, which is why the result is an int
.
To make the return value be a double
instead, simply change the literal 0
to 0.0
in the init
parameter:
return reduce(execution::seq, cbegin(coeffs), cend(coeffs), 0.0, ...);
compute mean using std::accumulate fails
It seems that gcc uses accumulate<vector<double>::iterator,int>
instead of accumulate<vector<double>::iterator,double>
. If you use the specific template values it will work:
cout << "mean: " << accumulate<vector<double>::iterator,double>(v.begin(), v.end(), 0, mean) << endl;
EDIT: This happens because the type T
in template< class InputIterator, class T >
is defined by your initial value
T accumulate0
, which is an integer. So use the line above or
cout << "mean: " << accumulate(v.begin(), v.end(), 0.0, mean) << endl;
References
- http://en.cppreference.com/w/cpp/algorithm/accumulate
- http://www.cplusplus.com/reference/std/numeric/accumulate/
How to sum up elements of a C++ vector?
Actually there are quite a few methods.
int sum_of_elems = 0;
C++03
Classic for loop:
for(std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it)
sum_of_elems += *it;Using a standard algorithm:
#include <numeric>
sum_of_elems = std::accumulate(vector.begin(), vector.end(), 0);Important Note: The last argument's type is used not just for the initial value, but for the type of the result as well. If you put an int there, it will accumulate ints even if the vector has float. If you are summing floating-point numbers, change
0
to0.0
or0.0f
(thanks to nneonneo). See also the C++11 solution below.
C++11 and higher
b. Automatically keeping track of the vector type even in case of future changes:
#include <numeric>
sum_of_elems = std::accumulate(vector.begin(), vector.end(),
decltype(vector)::value_type(0));Using
std::for_each
:std::for_each(vector.begin(), vector.end(), [&] (int n) {
sum_of_elems += n;
});Using a range-based for loop (thanks to Roger Pate):
for (auto& n : vector)
sum_of_elems += n;
C++17 and above
Using
std::reduce
which also takes care of the result type, e.g if you havestd::vector<int>
, you getint
as result. If you havestd::vector<float>
, you getfloat
. Or if you havestd::vector<std::string>
, you getstd::string
(all strings concatenated). Interesting, isn't it?auto result = std::reduce(v.begin(), v.end());
There are other overloads of this function which you can run even parallelly, in case if you have a large collection and you want to get the result quickly.
Related Topics
What Is _Declspec and When Do I Need to Use It
How to Use the Priority Queue Stl for Objects
Inserting into a Vector at the Front
Why Do You Use Typedef When Declaring an Enum in C++
How to Get the Maximum or Minimum Value in a Vector
Why Can't I Forward-Declare a Class in a Namespace Using Double Colons
Using Maven for C/C++ Projects
Where Would You Use a Friend Function VS. a Static Member Function
How to Typedef a Function Pointer with the C++11 Using Syntax
Removing Watermark Out of an Image Using Opencv
Hooking Directx Endscene from an Injected Dll
Is Python Faster and Lighter Than C++
Initializing the Size of a C++ Vector