Лучший способ вернуть 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 не устанавливал значение по умолчанию.
Я попробовал то же самое с изменением размера, которое намного медленнее.
Есть ли у вас какие-либо предложения, как это можно оптимизировать?

С уважением

2

Решение

Внедрение QVector делится своими данными ( http://qt-project.org/doc/qt-5.0/qtcore/implicit-sharing.html#implicitly-shared ) так что ты не делаешь ничего плохого.

5

Другие решения

Вы выделяете новый 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);
}

С помощью этого кода результирующий вектор выделяется только один раз.

3

Поскольку вы утверждаете, что «возврат» занимает больше всего времени, проблема может быть не в самой функции, а на сайте, где используется возвращаемое значение.

Увы, вот где ваш код тратит время:

  1. В распределении QVector каждый раз, когда вызывается среднее значение. Предположительно, он вызывается неоднократно, поэтому нет необходимости каждый раз выделять новый вектор.

  2. В QVector::operator[], У него немного больше накладных расходов, чем у простого доступа к массиву, потому что isDetached звонок сделан на каждый звонок operator[],

  3. В 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

QVector является общий класс. Копирование — это постоянная операция, которая должна быть очень быстрой.

2
По вопросам рекламы [email protected]