Я пытаюсь придумать хороший способ оценить следующую функцию
double foo(std::vector<double> const& x, double c = 0.95)
{
auto N = x.size(); // Small power of 2 such as 512 or 1024
double sum = 0;
for (auto i = 0; i != N; ++i) {
sum += (x[i] * pow(c, double(i)/N));
}
return sum;
}
Две мои основные проблемы с этой наивной реализацией — это производительность и точность. Поэтому я подозреваю, что самым тривиальным улучшением будет изменение порядка цикла: for (auto i = N-1; i != -1; --i)
(-1 зацикливается, это нормально). Это повышает точность, добавляя сначала меньшие термины.
Хотя это хорошо для точности, это сохраняет проблему производительности pow
. Численно pow(c, double(i)/N)
равно pow(c, (i-1)/N) * pow(c, 1/N)
. И последнее является константой. Так что теоретически мы можем заменить pow
повторным умножением. Хотя это хорошо для производительности, это вредит точности — ошибки будут накапливаться.
Я подозреваю, что здесь скрывается значительно лучший алгоритм. Например, тот факт, что N является степенью двойки, означает, что существует средний член x[N/2], который умножается на sqrt(c)
. Это намекает на рекурсивное решение.
В несколько связанном числовом наблюдении это выглядит как умножение сигнала на экспоненту, поэтому я, естественно, думаю: «БПФ, тривиальная свертка = сдвиг, ОБПФ», но это, похоже, не дает реальной выгоды с точки зрения точности или производительности.
Итак, это известная проблема с известными решениями?
expm1
кажется важным шагом во избежание потери точности. 10.07.2018x[i] + c^(1/N)*x[i+1]
ко всем четнымi
, а результат сохранил вx[i]
. Затем добавьтеx[i] + c^(2/N) * x[i+2]
, сохраните вx[i]
и так далее. 10.07.2018StDev(x) > Average(x)
, измеренные образцы непрерывного физического сигнала, поэтому нетривиальная корреляция между соседними значениями (определенно не IID). 10.07.2018