【问题标题】:In C++, how to compute the mean of a vector of integers using a vector view and gsl_stats_mean?在 C++ 中,如何使用向量视图和 gsl_stats_mean 计算整数向量的平均值?
【发布时间】:2011-01-31 15:57:00
【问题描述】:

我的程序处理 整数的 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)。任何的想法?提前致谢。

【问题讨论】:

  • +1 表示第一个问题问得很好。

标签: c++ vector gsl


【解决方案1】:

double* 的演员表非常可疑。

每当您想使用演员表时,请三思。然后寻找一种无需强制转换的方法(如果转换是隐式的,则可能通过引入临时变量)。然后在施放前三思而后行。

由于内存区域实际上不包含double 值,因此代码只是将那里的位模式解释为它们代表双精度值,具有可预见的不良影响。将 int* 转换为 double* 与转换数组的每个元素非常不同。

【讨论】:

  • 好的,从现在开始我会更加谨慎地使用演员表。 Mark B 也提出了一个临时向量的解决方案,但这是否意味着我的初始向量必须临时复制?如果这个向量很大怎么办?
【解决方案2】:

使用整数统计函数:

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

注意gsl_stats_int_mean 而不是gsl_stats_mean

【讨论】:

    【解决方案3】:

    除非你做很多比平均值复杂得多的统计数据,否则我会忽略 gsl 而只使用标准算法:

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

    当/如果使用统计库是合理的,您的首选可能应该是寻找设计更好的其他东西(例如,Boost Accumulators)。

    如果您出于某种原因决定确实需要使用 gsl,那么您似乎必须先将 ints 数组复制到 doubles 数组中,然后在结果。这显然是非常低效的,尤其是在处理大量数据时——因此之前的建议是使用其他东西。

    【讨论】:

    • 我正在编写一个模拟器,因此我需要一个 RNG 以及计算均值、var、sd、分位数等的函数。这就是为什么我想继续使用 GSL,而不是使用 std::accumulate。
    • @wfoolhill:标准库已经提供了 PRNG,Boost 累加器(以及许多其他)可以计算你提到的所有函数——比 gsl 甚至希望的更干净。
    • 我不了解 Boost,因此按照您的建议,我快速浏览了 Boost.Accumulator 的文档。它看起来确实非常强大,但我认为我不需要它的所有功能。到目前为止,我拥有 GSL 所需的一切。
    • @wfoolhill:当然,除了工作之外,您还需要一切。即使你解决了这个问题,它仍然只是“除了运作良好之外”。
    【解决方案4】:

    虽然我对 GSL 不熟悉,但 (double*) gsl_v.vector.data 的表达看起来非常可疑。您确定 reinterpret_cast 获取 double 数据的指针是正确的吗?

    【讨论】:

      【解决方案5】:

      投射到double* 会弄乱您的数据。它不是将数据转换为double,而是将int二进制数据用作double

      【讨论】:

        【解决方案6】:

        根据http://www.gnu.org/software/gsl/manual/html_node/Mean-and-standard-deviation-and-variance.htmlgsl_stats_mean 函数采用double 的数组。您正在获取 int 的 vector 并告诉它使用原始字节作为 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();
        

        【讨论】:

        • 谢谢,但是通过使用矢量视图,我想避免使用临时矢量,因为如果初始矢量非常大,我会浪费时间将其复制到临时矢量中......或者是“ tempForStats(stl_v.begin(), stl_v.end());"效率很高?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-04
        • 2014-06-26
        • 2019-11-26
        • 1970-01-01
        • 1970-01-01
        • 2014-05-16
        相关资源
        最近更新 更多