Как эффективно вычислить среднее на лету (скользящее среднее)?
Я придумал это
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 сохранения работает всего или пересчитал. Время для повторного вычисления-это высокая стоимость стоимость хранения числа, вероятно, низкая стоимость с точки зрения памяти, и код для повторного вычисления, безусловно, будет больше, чем место памяти для хранения суммы и итерации.