2012-02-17 29 views
21

Tengo la tarea de leer un archivo y obtener los puntajes promedio de las pruebas.¿Cómo obtener un promedio en C++?

Es bastante simple pero no me gusta cómo se hace el promedio.

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

¿Hay alguna manera de dividirlo por el número de puntajes de las pruebas? No pude encontrar nada como esto en el libro o desde google. Algo así como

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

Si el número de pruebas no se conoce hasta que haya leído la entrada, que había necesidad de un bucle para hacer un promedio de * n * números. – FrustratedWithFormsDesigner

+1

Paso 0: mover esto a Desbordamiento de pila. Está fuera de tema aquí. –

+4

Excelente pregunta y una excelente observación.La codificación dura '5' es a) mágica, y b) redundante. –

Respuesta

43

Si usted tiene los valores de un vector o una matriz, sólo tiene que utilizar std::accumulate de <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

Para explicar más sobre lo que dice @RiaD: Cuando divide números enteros en C (++), de manera predeterminada solo usa números enteros matemáticos, p. Ej. los resultados de la división se truncan, dejándole sin datos después de un punto decimal. Si los valores de su conjunto de datos son lo suficientemente grandes, no es un gran problema, pero cuando se trata de números más pequeños, no quiere perder esa precisión, podría resultar en un 0.75 convirtiéndose en un 0 plano. –

+0

Shouldn ' eso es un '0' en lugar de solo '0'? Porque sin el punto seguirá siendo cero si suma números en el rango (-0.5, 0.5). – ikku100

3

Paso 1. A través de la iteración (si se quiere hacer) o recursividad (si quieres ser valiente) colocar todos los resultados de las pruebas en una matriz (si quieres simplicidad y velocidad) o una ligada lista (si quieres flexibilidad pero lento)

Paso 2. iterar a través de la matriz/lista hasta llegar a la final; agregando el contenido de cada célula/nodo sobre la marcha. Mantenga un conteo de la celda/nodo en el que se encuentra actualmente a medida que avanza.

Paso 3. Toma la cuenta de la primera variable y se divide por la segunda variable que mantiene un registro de dónde estabas. Esto producirá la media.

+0

Es poco probable que la lista vinculada sea útil. Puede hacer que la creación de la lista sea ligeramente más eficiente (pero la complejidad amortizada es la misma si se sobreasigna, como la mayoría de los 'vectores'), pero hace que la suma y la longitud sean más complicadas, y 1/3 es una bonita mala puntuación. – delnan

+2

Esto está en mi cabeza por bastante. Simplemente conozco Cin Cout y algunas otras cosas más. –

+0

@Jordan Entonces esto proporcionará una gran oportunidad para aprender un poco más de lo que usted sabe. Las matrices o listas y las iteraciones son fundamentales para todos los lenguajes de la computadora: cuanto antes los aprenda, mejor. – Caleb

1

También puede calcular la media usando un número variable de argumentos. El principio de esta función es que una cantidad desconocida de argumentos se almacena en una pila y podemos tomarlos.

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 
} 

Y se puede usar esta función como:

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

Pero el número de argumentos debe coincidir con el n.

+5

Tenga cuidado con este código. No se garantiza que p funcione de la manera esperada, ya que depende de los detalles de implementación. Al menos en máquinas de 64 bits, si algunos argumentos se pasan a través de argumentos, este código no funcionará. Para implementarlo correctamente, mira va_start y co. También con C++ 11, hay plantillas varadicas que se pueden usar también. – MJD

0

Aquí es mi generalización de obtener el promedio de los elementos de un contenedor mediante la especificación de una función lambda para obtener cada valor y luego sumar:

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

El código de cliente Lo he comprobado con va como

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

se pregunta, ¿por qué nadie mencionó boost::accumulators. No es la más corta de las soluciones ya publicadas, pero se puede ampliar más fácilmente para valores estadísticos más generales. Como la desviación estándar o los momentos superiores.

#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 da buena solución:

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

he podido escribir por lo que el tipo de retorno automático deducir. Cuando lo intenté obtuve un resultado extraño para average(-2).

https://wandbox.org/permlink/brssPjggn64lBGVq

Cuestiones relacionadas