Подтвердить что ты не робот

Как получить среднее значение на С++?

У меня есть задание читать файл и выводить средние тестовые оценки.

Это довольно просто, но мне не нравится, как это делается в среднем.

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

Есть ли способ разделить его на количество тестов? Я не мог найти ничего подобного в книге или из Google. Что-то вроде

average = (test + test + test + test) / ntests;
4b9b3361

Ответ 1

Если у вас есть значения в векторе или массиве, просто используйте std::accumulate из <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();

Ответ 2

Шаг 1. Через итерацию (если вы хотите сделать) или рекурсия (если вы хотите быть храбрым) поместите все тестовые оценки в массив (если вы хотите простоту и скорость) или связанный список (если вам нужна гибкость но медленно)

Шаг 2. Перейдите через массив/список, пока не дойдете до конца; добавляя содержимое каждой ячейки / node по мере продвижения. Содержите подсчет какой ячейки /node, в которой вы сейчас находитесь, по ходу дела.

Шаг 3. Возьмите сумму из первой переменной и разделите ее на вторую переменную, которая отслеживает, где вы были. Это даст среднее значение.

Ответ 3

Вы также можете рассчитать среднее значение с использованием переменного количества аргументов. Принцип этой функции заключается в том, что неизвестное количество аргументов хранится в стеке, и мы можем их взять.

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
}

И вы можете использовать эту функцию, например:

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

Но число аргументов должно совпадать с n.

Ответ 4

Вот мое обобщение получения среднего значения элементов контейнера, указав лямбда-функцию для получения каждого значения, а затем добавьте:

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();
}

Код клиента, который я тестировал, выглядит как

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();});

Ответ 5

Интересно, почему никто не упомянул boost::accumulators. Это не кратчайший из уже размещенных решений, но его можно более легко расширить для получения более общих статистических значений. Как стандартное отклонение или более высокие моменты.

#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;
}

Ответ 6

С++ 11 дает хорошее решение:

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...);
}

Мне не удалось написать его, чтобы он автоматически выводил возвращаемый тип. Когда я попытался, я получаю странный результат для average(-2).

https://wandbox.org/permlink/brssPjggn64lBGVq