Как эффективно вычислить среднее на лету (скользящее среднее)?

Я придумал это

n=1;
curAvg = 0;
loop{
  curAvg = curAvg + (newNum - curAvg)/n;
  n++;
}

Я думаю, что основные моменты этого способа являются:
- Это позволяет избежать больших чисел (и возможного переполнения, если вы суммируете, а затем разделите)
- вы сохраняете один регистр (не нужно хранить сумму)

видите ли вы какие-либо подводные камни в этом решении? Вы лучше предложение?

2 ответов


ваше решение по существу является " стандартным "оптимальным онлайн-решением для поддержания бегущей дорожки среднего без хранения больших сумм, а также во время работы" онлайн", т. е. вы можете просто обрабатывать одно число за раз, не возвращаясь к другим номерам, и вы используете только постоянный объем дополнительной памяти. Если вы хотите немного оптимизированное решение с точки зрения численной точности, за счет того, чтобы быть "онлайн", то, предполагая, что все ваши номера неотрицательны, сначала отсортируйте свои номера из от наименьшего к наибольшему, а затем обрабатывайте их в этом порядке, так же, как и сейчас. Таким образом, если вы получите кучу чисел, которые действительно малы примерно равны, а затем вы получите одно большое число, вы сможете точно вычислить среднее без underflow, в отличие от того, если вы сначала обработали большое число.


приведенная выше формула-чепуха. Простая математика и точность диктовали бы:

n - это счетчик итераций, AV работает в среднем,newVal - это новое значение

инициализации n=0, AV=0

( (AV * n) + newVal ) / (n+1) = AV

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