2011-01-31 17 views
7

mi programa manipula vectores STL de enteros pero, de vez en cuando, necesito calcular algunas estadísticas sobre ellos. Por lo tanto, utilizo las funciones GSL. Para evitar copiar el vector STL en un vector GSL, creo un GSL vector visión, y darle a las funciones de GSL, como en este trozo de código:En C++, ¿cómo calcular la media de un vector de números enteros utilizando una vista de vector y gsl_stats_mean?

#include <iostream> 
#include <vector> 
#include <gsl/gsl_vector.h> 
#include <gsl/gsl_statistics.h> 
using namespace std; 

int main(int argc, char* argv[]) 
{ 
    vector<int> stl_v; 
    for(int i=0; i<5; ++i) 
    stl_v.push_back(i); 

    gsl_vector_int_const_view gsl_v = gsl_vector_int_const_view_array(&stl_v[0], stl_v.size()); 

    for(int i=0; i<stl_v.size(); ++i) 
    cout << "gsl_v_" << i << "=" << gsl_vector_int_get(&gsl_v.vector, i) << endl; 

    cout << "mean=" << gsl_stats_mean((double*) gsl_v.vector.data, 1, stl_v.size()) << endl; 
} 

Una vez compilado (gcc -lstdC++ -lgsl test.cpp -lgslcblas), este código muestra esto:

gsl_v_0=0 
gsl_v_1=1 
gsl_v_2=2 
gsl_v_3=3 
gsl_v_4=4 
mean=5.73266e-310 

la vista vector se creó correctamente pero no entiendo por qué la media es incorrecto (debe ser igual a 10/5 = 2). ¿Alguna idea? Gracias por adelantado.

+1

+1 para una primera pregunta bien hecha. – aschepler

Respuesta

3

Use las funciones estadísticas del número entero:

cout << "mean=" << gsl_stats_int_mean(gsl_v.vector.data, 1, stl_v.size()) << endl; 

Nota del gsl_stats_int_mean en lugar de gsl_stats_mean.

4

El molde a double* es muy sospechoso.

Cada vez que tenga la tentación de usar un yeso, piénselo de nuevo. Luego busque una forma de hacerlo sin un elenco (tal vez mediante la introducción de una variable temporal si la conversión es implícita). Luego piensa una tercera vez antes de lanzar.

Dado que la región de memoria no contiene valores de double, el código simplemente interpreta los patrones de bits allí como si representaran dobles, con efectos predeciblemente no deseados. Lanzar un int* a double* es MUY diferente de fundir cada elemento de la matriz.

+0

Ok, de ahora en adelante seré más cauteloso con el reparto. Mark B también propuso una solución con un vector temporal, pero ¿esto significa que mi vector inicial debe copiarse temporalmente? ¿Qué pasa si este vector es muy grande? – tflutre

1

Aunque no estoy familiarizado con GSL, la expresión (double*) gsl_v.vector.data parece extremadamente sospechosa. ¿Está seguro de que es correcto reinterpret_cast ese puntero para obtener datos de double?

1

Casting a double* está arruinando sus datos. No es la conversión de datos en double, pero sólo utilizando int datos binarios como double

1

Según http://www.gnu.org/software/gsl/manual/html_node/Mean-and-standard-deviation-and-variance.html la función gsl_stats_mean toma una matriz de double. Estás tomando un vector de int y diciéndole que use los bytes sin formato como double, lo que no va a funcionar bien.

Tendrá que establecer un temporal vector de doble acontecerá en:

// Assumes that there's at least one item in stl_v. 
std::vector<double> tempForStats(stl_v.begin(), stl_v.end()); 
gsl_stats_mean(&tempForStats[0], 1, tempForStats.size()); 

EDIT: También es posible usar los algoritmos de la biblioteca estándar de hacer lo mismo int significa:

// Assumes that there's at least one item in stl_v. 
double total = std::accumulate(stl_v.begin(), stl_v.end(), 0); 
double mean = total/stl_v.size(); 
+0

Gracias, pero al usar una vista vectorial, quería evitar un vector temporal porque, si el vector inicial es muy grande, perderé el tiempo copiándolo en uno temporal ... ¿O es "tempForStats (stl_v.begin() , stl_v.end()); ¿muy eficiente? – tflutre

2

A menos que esté haciendo muchas estadísticas considerablemente más complejas que la media, ignoraría gsl y solo usaría algoritmos estándar:

double mean = std::accumulate(stl_v.begin(), stl_v.end(), 0.0)/stl_v.size(); 

Cuando/si se justifica el uso de una biblioteca de estadísticas, su primera opción probablemente sea buscar otra cosa que esté mejor diseñada (por ejemplo, Acumuladores Boost).

Si decide, por cualquier razón, que realmente necesita usar GSL, parece que vas a tener que copiar su gama de int s de una serie de double s en primer lugar, a continuación, utilizar GSL en el resultado.Esto es obvio, bastante ineficiente, especialmente si se trata de una gran cantidad de datos, por lo tanto, el consejo anterior de usar algo más en su lugar.

+1

Estoy escribiendo un simulador, así que necesito un RNG así como funciones para calcular la media, var, sd, cuantiles, etc. Es por eso que me gustaría seguir usando GSL y no usar std :: accumulate. – tflutre

+0

@wfoolhill: la biblioteca estándar ya proporciona PRNG, y los acumuladores de Boost (entre muchos otros) pueden calcular todas las funciones que ha mencionado, mucho más limpias de lo que gsl espera. –

+0

No sé Boost, siguiendo así su consejo, eché un vistazo rápido a la documentación de Boost.Accumulator. Parece realmente muy poderoso, pero no creo que necesite todas sus funcionalidades. Tengo todo lo que necesito con el GSL hasta ahora. – tflutre

Cuestiones relacionadas