В C ++, как вычислить среднее значение вектора целых чисел с использованием векторного представления и gsl_stats_mean? - PullRequest
7 голосов
/ 31 января 2011

моя программа манипулирует векторами STL целых чисел , но время от времени мне нужно вычислять некоторые статистические данные по ним.Поэтому я использую функции GSL .Чтобы избежать копирования вектора STL в вектор GSL, я создаю векторное представление GSL и передаю его функциям GSL, как показано в следующем фрагменте кода:

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

После компиляции(gcc -lstdc ++ -lgsl -lgslcblas test.cpp), этот код выводит следующее:

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

Векторное представление создано правильно, но я не понимаю, почему среднее значение является неправильным (оно должно быть равно10/5 = 2).Любая идея?Заранее спасибо.

Ответы [ 6 ]

4 голосов
/ 31 января 2011

Приведение к double* очень подозрительно.

Каждый раз, когда у вас возникает соблазн использовать актерский состав, подумайте еще раз. Затем найдите способ сделать это без приведения (возможно, путем введения временной переменной, если преобразование неявное). Затем подумайте в третий раз, прежде чем читать.

Поскольку область памяти на самом деле не содержит double значений, код просто интерпретирует там битовые комбинации, как если бы они представляли двойные числа, с предсказуемо нежелательными эффектами. Приведение int* к double* ОЧЕНЬ отличается от приведения каждого элемента массива.

3 голосов
/ 31 января 2011

Используйте функции целочисленной статистики:

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

Обратите внимание на gsl_stats_int_mean вместо gsl_stats_mean.

2 голосов
/ 31 января 2011

Если вы не делаете большую статистику, значительно более сложную, чем среднее, я бы проигнорировал gsl и просто использовал стандартные алгоритмы:

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

Когда / если использование статистической библиотеки оправдано, вашпервый выбор, вероятно, должен искать что-то еще, что лучше разработано (например, Boost Accumulators).

Если вы решите, по какой-то причине, что вам действительно нужно использовать gsl, похоже, вам придетсясначала скопируйте ваш массив int s в массив double s, а затем используйте gsl для результата.Это очевидно совершенно неэффективно, особенно если вы имеете дело с большим количеством данных - таким образом, предыдущий совет использовать что-то другое.

1 голос
/ 31 января 2011

Согласно http://www.gnu.org/software/gsl/manual/html_node/Mean-and-standard-deviation-and-variance.html функция gsl_stats_mean принимает массив double.Вы берете vector от int и говорите ему использовать необработанные байты как double, что не будет работать правильно.

Вам нужно будет установить временный vector изdouble для передачи:

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

РЕДАКТИРОВАТЬ: Вы также можете использовать стандартные библиотечные алгоритмы, чтобы сделать int сам по себе:

// 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();
1 голос
/ 31 января 2011

Приведение к double* портит ваши данные. Это не преобразование данных в double, а просто использование int двоичных данных как double

1 голос
/ 31 января 2011

Хотя я не знаком с GSL, выражение (double*) gsl_v.vector.data выглядит крайне подозрительно. Вы уверены, что reinterpret_cast этот указатель является правильным для получения double данных?

...