我试图从一个应该计算移动平均值的函数返回一个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不设置默认值。 我尝试调整大小的速度要慢得多。 您对如何优化它有什么建议吗?
此致
答案 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)
由于您声称“返回”时间过长,问题可能不在函数本身,而是在使用返回值的站点。
唉,这是你的代码浪费时间的地方:
每次调用平均值时分配QVector
。据推测它被重复调用,因此不需要每次都分配新的矢量。
在QVector::operator[]
中。它比普通数组访问有更多的开销,因为每次调用isDetached
时都会进行这个令人讨厌的operator[]
调用。
在QVector::append
中。它不仅会调用isDetached
,还会检查并修改长度。
请注意,返回您的值绝对没有错。这是一项微不足道的操作,并且很快就能完成。在返回时你做得很好 - 只返回。但是你没有告诉我们你如何使用返回的值,所以我不能告诉你是否你在那里做错了。
为了防止重复分配和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)
QVector
是a shared class。复制是一个持续的操作,应该非常快。