2012-02-17 13 views
21

Mam zadanie odczytu pliku i wyprowadzenia średnich wyników testu.Jak uzyskać średnią w C++?

Jest to dość proste, ale nie podoba mi się sposób, w jaki średnia jest wykonywana.

average = (test1 + test2 + test3 + test4 + test5)/5.0; 

Czy istnieje sposób na podzielenie go przez liczbę wyników testu? Nie mogłem znaleźć czegoś takiego w książce lub w google. Coś jak

average = (test + test + test + test)/ntests; 
+0

Jeżeli liczba testów nie jest znana aż czytać wejście, to trzeba zrobić pętlę średnio * n * liczb. – FrustratedWithFormsDesigner

+1

Krok 0: Przenieś to do przepełnienia stosu. To nie temat. –

+4

Doskonałe pytanie i doskonała obserwacja.Hardcoding "5" jest a) magią, i b) zbędnym. –

Odpowiedz

43

Jeśli masz wartości w wektorze lub tablicy, wystarczy użyć std::accumulate od <numeric>:

std::vector<double> vec; 
// ... fill vec with values (do not use 0; use 0.0) 
double average = std::accumulate(vec.begin(), vec.end(), 0.0)/vec.size(); 
+0

Aby wyjaśnić, co mówi @RiaD: Kiedy dzielisz liczby całkowite w C (++), domyślnie używa się tylko matematyki całkowitej - np. wyniki dzielenia są obcinane, dzięki czemu nie ma danych po kropce dziesiętnej. Jeśli wartości zestawu danych są wystarczająco duże, nie jest to zbyt duży problem, ale w przypadku mniejszych liczb nie chcesz stracić tej dokładności, może to spowodować przekształcenie 0.75 w płaskie 0. –

+0

Shouldn ' t to będzie "0" zamiast tylko "0"? Ponieważ bez kropki pozostanie zero, jeśli dodasz liczby w zakresie (-0,5, 0,5). – ikku100

3

Krok 1. Via iteracji (jeśli chcesz być zrobione) lub rekursji (jeśli chcesz być odważny) umieścić wszystkie wyniki testów do tablicy (jeśli chcesz prostotę i szybkość) lub połączone lista (jeśli chcesz elastyczności, ale powoli)

Krok 2. Przeliczuj tablicę/listę aż do końca; dodawanie zawartości każdej komórki/węzła podczas podróży. Sprawdź liczbę komórek/węzłów, w których aktualnie się znajdujesz.

Krok 3. Weź sumę z pierwszej zmiennej i podziel ją przez drugą zmienną, która zapisywała, gdzie byłeś. To da średnią.

+0

Powiązana lista raczej nie będzie przydatna. Może sprawić, że budowanie listy będzie nieco bardziej efektywne (ale zamortyzowana złożoność jest taka sama, jeśli przesadzisz, jak większość 'wektora' 'do), ale sprawia, że ​​sumowanie i znajdowanie długości jest bardziej skomplikowane, a 1/3 jest ładnym zły wynik. – delnan

+2

To trochę ponad moją głowę. Po prostu znam cue cout i kilka innych rzeczy. –

+0

@Jordan To będzie świetna okazja, aby dowiedzieć się trochę więcej niż wiesz. Tablice lub listy i iteracja są podstawą wszystkich języków komputerowych - im szybciej się ich nauczysz, tym lepiej. – Caleb

1

Można również obliczyć średnią za pomocą zmiennej liczby argumentów. Zasada tej funkcji, że nieznana liczba argumentów jest przechowywana w stosie i możemy je pobrać.

double average(int n, ...)   // where n - count of argument (number) 
{ 
    int *p = &n;     // get pointer on list of number in stack 
    p++;       // get first number 
    double *pp = (double *)p;  // transformation of the pointer type 
    double sum = 0; 
    for (int i = 0; i < n; pp++, i++) //looking all stack 
     sum+=(*pp);     // summarize 
    return sum/n;    //return average 
} 

I można za pomocą tej funkcji, takich jak:

double av1 = average(5, 3.0, 1.5, 5.0, 1.0, 2.0); 
double av2 = average(2, 3.0, 1.5); 

Ale liczba argumentów musi być zgodny z n.

+5

Uważaj na ten kod. Nie gwarantuje to, że praca będzie wyglądać tak, jak tego oczekujesz, ponieważ polegasz na szczegółach implementacji. Przynajmniej na maszynach 64-bitowych, gdy argumenty są przekazywane za pomocą argumentów, ten kod nie zadziała. Aby poprawnie zaimplementować, spójrz na va_start i co. Również w wersji C++ 11 można używać szablonów varadic. – MJD

0

Oto moja uogólnienie uzyskanie średnio elementów kontenera określając funkcję lambda, aby uzyskać każdą wartość, a następnie dodać:

template <typename ForwardIterator, typename F> 
double inline averageOf (ForwardIterator first, ForwardIterator last, F function) { 
    std::vector<typename std::result_of<F(typename ForwardIterator::value_type)>::type> values; 
    while (first != last) { 
     values.emplace_back (function(*first)); 
     ++first; 
    } 
    return static_cast<double>(std::accumulate (values.begin(), values.end(), 0))/values.size(); 
} 

Kod klienta Testowałem go idzie jak

const std::list<CharmedObserver*> devotees = 
    charmer->getState<CharmerStateBase>(CHARMER)->getDevotees(); 
const int averageHitPointsOfDevotees = averageOf (devotees.begin(), devotees.end(), 
    [](const CharmedObserver* x)->int {return x->getCharmedBeing()->getHitPoints();}); 
0

Zastanawiasz się, dlaczego nikt nie wspomniał o boost::accumulators. Nie jest to najkrótszy z już opublikowanych rozwiązań, ale można go łatwiej rozszerzyć na bardziej ogólne wartości statystyczne. Jak standardowe odchylenie lub wyższe momenty.

#include <iostream> 
#include <boost/accumulators/accumulators.hpp> 
#include <boost/accumulators/statistics/stats.hpp> 
#include <boost/accumulators/statistics/mean.hpp> 
#include <algorithm> 
#include <vector> 

double mean(const std::vector<double>& values) { 
    namespace bo = boost::accumulators; 

    if (values.empty()) return 0.; 
    bo::accumulator_set<double, bo::stats<bo::tag::mean>> acc; 
    acc=std::for_each(values.begin(), values.end(), acc); 
    return bo::mean(acc); 
} 

int main() 
{ 
    std::vector<double> test = { 2.,6.,4.,7. }; 
    std::cout << "Mean: " << mean(test) << std::endl; 
    std::cout << "Mean: " << mean({}) << std::endl; 

    return 0; 
} 
0

C++ 11 daje miłe rozwiązanie:

constexpr auto countArguments() -> size_t 
{ 
    return 0; 
} 

template<class T1, class ... Ti> 
constexpr auto countArguments(T1, Ti ...xi) -> size_t 
{ 
    return 1 + countArguments(xi...); 
} 

template<class T> 
constexpr auto sumAruguments(T x) -> double 
{ 
    return x; 
} 

template<class T1, class ... Ti> 
constexpr auto sumAruguments(T1 x1, Ti ...xi) -> double // decltype(x1 + sumAruguments(xi...)) 
{ 
    return x1 + sumAruguments(xi...); 
} 

template<class...T> 
constexpr auto avarage(T...xi) -> double 
{ 
    return sumAruguments(xi...)/countArguments(xi...); 
} 

byłem w stanie napisać go tak typ zwracany auto-wywieść. Gdy próbowałem, otrzymuję dziwny wynik dla average(-2).

https://wandbox.org/permlink/brssPjggn64lBGVq

Powiązane problemy