2011-01-31 7 views
7

il mio programma manipola i vettori STL di numeri interi ma, di volta in volta, ho bisogno di calcolare alcune statistiche su di essi. Pertanto utilizzo le funzioni GSL. Per evitare di copiare il vettore STL in un vettore GSL, creo un GSL vettore vista, e dare alle funzioni GSL, come in questo pezzo di codice:In C++, come calcolare la media di un vettore di numeri interi usando una vista vettoriale e 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 volta compilato (gcc -lstdC++ -lgsl -lgslcblas test.cpp), questo codice Risulterà:

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

il vettore vista viene creato correttamente, ma non capisco il motivo per cui la media è sbagliato (dovrebbe essere uguale a 10/5 = 2). Qualche idea? Grazie in anticipo.

+1

+1 per una prima domanda ben fatta. – aschepler

risposta

3

utilizzare le statistiche intere funzioni:

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

Nota la gsl_stats_int_mean invece di gsl_stats_mean.

4

Il cast a double* è molto diffidente.

Ogni volta che si è tentati di utilizzare un cast, ripensateci. Quindi cerca un modo per farlo senza un cast (magari introducendo una variabile temporanea se la conversione è implicita). Quindi pensa una terza volta prima di lanciare.

Poiché la regione di memoria in realtà non contiene valori double, il codice sta semplicemente interpretando i modelli di bit lì come se rappresentassero i doppi, con effetti prevedibilmente indesiderati. La trasmissione di un numero da int* a double* è MOLTO diversa dal cast di ciascun elemento dell'array.

+0

Ok, d'ora in poi sarò più cauto con il cast. Mark B ha anche proposto una soluzione con un vettore temporaneo, ma questo significa che il mio vettore iniziale deve essere copiato temporaneamente? Cosa succede se questo vettore è molto grande? – tflutre

1

Anche se non ho familiarità con GSL, l'espressione (double*) gsl_v.vector.data sembra estremamente sospetta. Sei sicuro che sia corretto a reinterpret_cast quel puntatore per ottenere i dati double?

1

La trasmissione a double* fa confusione dei dati. Non è la conversione dei dati in double, ma semplicemente utilizzando int dati binari come double

1

Secondo http://www.gnu.org/software/gsl/manual/html_node/Mean-and-standard-deviation-and-variance.html funzione gsl_stats_mean accetta un array di double. Stai prendendo un vector di int e dicendogli di utilizzare i byte non elaborati come double che non funzionerà correttamente.

Avrai bisogno di impostare una temporanea vector di doppio a passare in:

// 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: Si potrebbe anche usare gli algoritmi della libreria standard per fare l'int significa te stesso:

// 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

Grazie, ma utilizzando una vista vettoriale, volevo evitare un vettore temporaneo perché, se il vettore iniziale è molto grande, perderò il tempo copiandolo in uno temporaneo ... O è "tempForStats (stl_v.begin() , stl_v.end()); " molto efficiente? – tflutre

2

A meno che tu non stia facendo statistiche molto più complesse della media, ignorerei gsl e userei solo algoritmi standard:

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

Quando/se utilizzare una libreria statistica è giustificato, la prima scelta dovrebbe probabilmente essere quella di cercare qualcos'altro che sia meglio progettato (ad esempio, Accumulatori Boost).

Se si decide, per qualsiasi motivo, che si ha realmente bisogno di usare GSL, sembra che dovrete copiare l'array di int s ad una serie di double s prima, quindi utilizzare GSL sul risultato.Questo è ovvio abbastanza inefficiente, specialmente se hai a che fare con molti dati - quindi il consiglio precedente di usare qualcos'altro.

+1

Sto scrivendo un simulatore, quindi ho bisogno di un RNG così come di funzioni per calcolare media, var, sd, quantili e così via. Ecco perché vorrei continuare a utilizzare GSL e non utilizzare std :: accumulate. – tflutre

+0

@wfoolhill: la libreria standard fornisce già PRNG e gli accumulatori Boost (tra molti altri) possono calcolare tutte le funzioni che hai menzionato - molto più chiaramente di quanto gsl speri di fare. –

+0

Non so Boost, quindi seguendo il tuo consiglio, ho dato una rapida occhiata alla documentazione di Boost.Accumulator. Sembra davvero molto potente, ma non credo di aver bisogno di tutte le sue funzionalità. Ho tutto ciò di cui ho bisogno con il GSL fino ad ora. – tflutre