返回QVector的最佳方式

时间:2014-01-26 17:04:43

标签: c++ qt optimization qvector

我试图从一个应该计算移动平均值的函数返回一个QVector。我的问题是如何使功能更有效。数学很好,我更想知道如果我在返回QVector时做错了什么。这是我到目前为止的守则:

QVector<double> moving_exponential_average(const QVector<double>& a, double lambda) {
        if(lambda <0 ) {
            lambda = 0;
        }
        if(lambda >1) {
            lambda = 1;
        }
        QVector<double> b;
        b.reserve(a.size());

        b.append(a[0]);
        double l_inv = 1-lambda;
        for(unsigned int i = 1; i < a.size(); ++i) {
            b.append(a[i]*lambda+l_inv*b[i-1]);
        }
        return b;
    }

我使用默认构造函数来保持QVector不设置默认值。 我尝试调整大小的速度要慢得多。 您对如何优化它有什么建议吗?

此致

4 个答案:

答案 0 :(得分:5)

QVector实现共享其数据(http://qt-project.org/doc/qt-5.0/qtcore/implicit-sharing.html#implicitly-shared),因此您没有做错任何事。

答案 1 :(得分:3)

您正在为每次通话分配新的QVector。 另一种方法是将输入向量和输出向量提供给函数:

void moving_exponential_average(const QVector<double> &a, QVector<double> &b, double lambda)
{
    //store result in b vector
    //do not use append but use the [] operator, like
    b[0] = a[0];
    ...
    b[i] = a[i] * lambda + l_inv * b[i - 1];
}

QVector<double> a;
QVector<double> b;  //make same size as a
//then repeatedly call
while (notDone) {
    update(a);
    moving_exponential_average(a, b, lambda);
}

使用此代码,结果向量仅分配一次。

答案 2 :(得分:3)

由于您声称“返回”时间过长,问题可能不在函数本身,而是在使用返回值的站点。

唉,这是你的代码浪费时间的地方:

  1. 每次调用平均值时分配QVector。据推测它被重复调用,因此不需要每次都分配新的矢量。

  2. QVector::operator[]中。它比普通数组访问有更多的开销,因为每次调用isDetached时都会进行这个令人讨厌的operator[]调用。

  3. QVector::append中。它不仅会调用isDetached,还会检查并修改长度。

  4. 请注意,返回您的值绝对没有错。这是一项微不足道的操作,并且很快就能完成。在返回时你做得很好 - 只返回。但是你没有告诉我们你如何使用返回的值,所以我不能告诉你是否你在那里做错了。

    为了防止重复分配和operator[]开销,您可以使用一个类来保持向量可以重用,并使用指针到向量的数据而不是直接使用向量。

    为了让它更快,可能需要使用SIMD内在函数。

    class Averager {
      QVector<double> m_result;
      Q_DISABLE_COPY(Averager)
    public:
      QVector<double> movingExponentialAverage(const QVector<double> & a, double lambda) {
        if (lambda < 0) lambda = 0; else if (lambda > 1) lambda = 1;
        m_result.resize(a.size());
        double * b = m_result.data();
        double lInv = 1-lambda;
        for(int i = 1; i < a.size(); ++i) {
          b[i] = a[i] * lambda + b[i-1] * l_inv;
        }
        return m_result;
      }
    };
    
    void test() {
      Averager avg; 
      QVector<double> src;
      while (true) {
        update(src);
        const QVector<double> & dst = avg.movingExponentialAverage(src, 0.2);
        ...
      } 
    

答案 3 :(得分:2)

QVectora shared class。复制是一个持续的操作,应该非常快。