20

I am trying to write a program where the user inputs as many numbers as they want and then the program returns the average of the numbers. So far the program only outputs the last number entered.

#include <vector>
#include <iostream>
#include <numeric>


using namespace std;

int main()
{  
    vector<float> v;
    int input;

    cout << " Please enter numbers you want to find the mean of:" <<endl;
    while (cin >> input);
    v.push_back(input);

float average = accumulate( v.begin(), v.end(), 0.0/ v.size());
cout << "The average is" << average << endl;

return 0;  

}
alfiej12
  • 371
  • 3
  • 4
  • 15
  • I think you've got the Maths wrong. And the data type is strange too. –  Feb 18 '15 at 01:24
  • @NickyC To find the average of a set of number you do the sum of the numbers divided by how many there are don't you? and my program just seems to return the last number entered. – alfiej12 Feb 18 '15 at 01:27
  • @noodlebar: you code is messed up, you put /v.size() in the wrong place, it looks like you just copy paste it from somewhere. – swang Feb 18 '15 at 01:30
  • What @swang say is where you get the Maths wrong. –  Feb 18 '15 at 01:33
  • @noodlebar Put it after the `)` of `std::accumulate`. –  Feb 18 '15 at 01:34
  • @noodlebar: have you read mine and other's answer? – swang Feb 18 '15 at 01:36
  • @noodlebar Do you realize your code (which is wrong) mismatches your understanding of average (which is correct)? –  Feb 18 '15 at 01:36
  • @swang Thank you both, the code now works, i have changed it to double instead of float, and debugged it. Works perfectly now. – alfiej12 Feb 18 '15 at 01:45
  • 1
    Is the vector (or storing of the values) a requirement? An average of items doesn't need to store the items; only sum their values and count the items. – Thomas Matthews Feb 18 '15 at 02:08

4 Answers4

72

In C++17 and higher, you should prefer std::reduce over std::accumulate. Both calculate the sum, but std::reduce has higher numerical stability and, less importantly, is potentially faster because it might be parallelized.

#include <vector>
#include <numeric>
#include <iostream>

float average(std::vector<float> const& v){
    if(v.empty()){
        return 0;
    }

    auto const count = static_cast<float>(v.size());
    return std::reduce(v.begin(), v.end()) / count;
}

int main(){
    std::vector<float> v{8, 4, 2, 7, 5};
    auto const a = average(v);
    std::cout << "average: " << a << "\n";
}

Note that static_cast suppresses a compile warning here, that std::size_t (the type of v.size()) with 8 byte size can theoretically express values for which the precision of a 4 byte float is not sufficient.


Your code has two bug. First get rid of semi-colon after while

while (cin >> input); // <-- bug
v.push_back(input);   // not in loop

// fixed loop
while (cin >> input){
    v.push_back(input);
}

Second your average calculation is wrong. The third argument of std::accumulate is the initial value of the sum, which is 0 by default, so you don't need to pass it.

Your actual bug is, that you divided the 0 by the element count. What you wanted, was to divide the value sum by the element count.

float average = accumulate(v.begin(), v.end(), 0.0 / v.size());
//                                             ^^^^^^^^^^^^^^

// fixed code
float average = accumulate(v.begin(), v.end(), 0.0) / v.size();

// without explicit init value
float average = accumulate(v.begin(), v.end()) / v.size();

// C++17 version with higher numerical stability
float average = reduce(v.begin(), v.end()) / v.size();

Also, the element of container data type should match the container type or if your really want to read integers and add to a float vector, you should use static_cast. The bulky syntax not only suppresses any compiler warnings, but also makes it clear that this is not an oversight, but an intentional difference in data types.

vector<float> v; // float vector
int input;       // integer input value
// ...
v.push_back(input); // add int value to float container

// an intentional type conversion should catch the eye
v.push_back(static_cast<float>(input));
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
P0W
  • 46,614
  • 9
  • 72
  • 119
  • 4
    And then someone will try to find the average of an empty range... boom! – Tom Feb 14 '20 at 07:35
  • 1
    @Tom Updated the post. – P0W Feb 14 '20 at 07:47
  • Note of caution - should std::reduce cause you to exceed int max - it will wrap - and your average will be wrong (not as pertinent for int as you'd need to go some to reach max - but if you use this for char....) – Danaldo Nov 08 '21 at 11:56
  • It wont help if exceeding int max - but if using std::vector v; can use std::reduce(v.begin(), v.end(), int(0)); to force int addition before creating the average – Danaldo Nov 08 '21 at 12:19
  • What `const&` means on `float average(std::vector const& v){`? Is it the same as `float average(const std::vector& v){`? – KcFnMi Feb 08 '23 at 16:19
13

There are quite a few bugs in your code, have you actually debugged it? here's a working version:

#include <vector>                                                               
#include <iostream>                                                             
#include <numeric>                                                              


using namespace std;                                                            

int main()                                                                      
{                                                                               
    vector<float> v;                                                            
    float input;                                                                

    cout << " Please enter numbers you want to find the mean of:" <<endl;       
    while (cin >> input)                                                        
        v.push_back(input);                                                     

    float average = accumulate( v.begin(), v.end(), 0.0)/v.size();              
    cout << "The average is" << average << endl;                                

    return 0;                                                                   

}    
swang
  • 5,157
  • 5
  • 33
  • 55
2

The third argument to std::accumulate is the initial value, so you start with 0.0 / v.size() (which is very small) and then add all items in the vector.

Instead you should use a value of zero as initial value, and after you calculated the total of all values in the vector then you divide by the size.

And as others pointed out, you only add the last value to the vector.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

You can use vector_name.size() to get the number of elements in vector. Here's my attempt for to compute average:

  #include <iostream>
  #include <vector>

   //function to compute average
   double compute_average(std::vector<int> &vi) {

     double sum = 0;

     // iterate over all elements
     for (int p:vi){

        std::cout << "p is " << p << std::endl;
        sum = sum + p;
     }

     return (sum/vi.size());
    }

    int main(){

        std::vector <int>vi =  {5,10};
        double val;

        val = compute_average(vi);

        std::cout << "avg is " << val << std::endl;
        return 0;   
    }