Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::accumulate doesn't give the expected sum

Tags:

c++

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?

like image 415
user435354 Avatar asked Aug 30 '10 21:08

user435354


4 Answers

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.

like image 92
Khaled Alshaya Avatar answered Nov 18 '22 10:11

Khaled Alshaya


You're calling accumulate with 0 as the init argument, so it'll accumulate using integer maths. Use 0.0 instead.

like image 43
Oliver Charlesworth Avatar answered Nov 18 '22 10:11

Oliver Charlesworth


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) };
like image 9
Andreas DM Avatar answered Nov 18 '22 11:11

Andreas DM


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.

like image 6
AnT Avatar answered Nov 18 '22 12:11

AnT