C++ std::accumulate doesn't give the expected sum
double numbers[ ] = { 1, 0.5 ,0.333333 ,0.25 ,0.2, 0.166667, 0.142857, 0开发者_运维技巧.125,
0.111111, 0.1 } ;
std::vector<double> doublenumbers ( numbers , numbers + 10 ) ;
std::cout << std::accumulate ( doublenumbers.begin( ) , doublenumbers.end( ) , 0 ) ;
This produces 1, which is evidently wrong. Any explanations?
You should write the following:
std::cout <<
std::accumulate ( doublenumbers.begin( ) , doublenumbers.end( ) , 0.0 ) ;
Because the type of 0 is int
.
When std::accumulate
is instantiated with the type of the third argument is int
, then it would convert the right hand side of the sum. e.g.:
result += *iter;
// int += double
This would force a conversion of double
to int
, instead of what you were thinking of which is the opposite.
You're calling accumulate
with 0
as the init
argument, so it'll accumulate using integer maths. Use 0.0
instead.
std::accumulate
will start to sum the type that is passed as 3rd argument, if you pass an integer, the return type will be int
. And in this case implicitly converted to a double
.
In C++11 and C++14, if you want to prevent narrowing conversion, you could create an object using direct-list-initialization:
double sum { std::accumulate(doublenumbers.begin(), doublenumbers.end(), 0) };
The compiler will then give you a warning saying that you are trying to convert from int to double and also at which line. This will save you debugging time. And you can easily fix it so that it becomes correct:
double sum { std::accumulate(doublenumbers.begin(), doublenumbers.end(), 0.0) };
std::accumulate ( doublenumbers.begin( ) , doublenumbers.end( ) , .0 ) ;
or
std::accumulate ( doublenumbers.begin( ) , doublenumbers.end( ) , (double) 0 ) ;
The type of the "accumulator" variable is the type of the last argument of std::accumulate
. You supplied 0
as an argument - an int
literal - which means that the accumulator will have type int
. The "accumulation" is done in an int
accumulator (i.e. rounded to int
after each individual summation) and produces int
result. In this case it is, apparently, 1
.
std::accumulate<double> (doublenumbers.begin(), doublenumbers.end(), 0); // also works
Just want to add (maybe) another useful answer.
For those who got wrong sum on unsigned long long int
or long long int
, you need to cast the init value to that particular type.
std::accumulate(vec.begin(), vec.end(), (long long int) 0) // or (unsigned long long int)
or you can automatically cast based on the vector type:
std::accumulate(vec.begin(), vec.end(), decltype(vec)::value_type(0))
精彩评论