Я пытаюсь придумать хороший способ оценить следующую функцию
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