Running Average

Live example of http://stackoverflow.com/questions/12636613/how-to-calculate-moving-average-without-keeping-the-count-and-data-total

by drzaus

HTML

<pre id="log"></pre>

JavaScript

(function(){
  // just so we can see something, in console too
	var $log = document.getElementById('log');
	function log(args) {
		args = Array.prototype.slice.call(arguments);
		console.log.apply(console, args);
		var msg = args[0].replace(/\%d/g, '%s');
		if(args.length > 1) {
			var tokens = args.slice(1);
			for(var i = 0; i < tokens.length; i++) msg = msg.replace('%s', tokens[i])
		}
		$log.innerHTML = $log.innerHTML + '\n' + msg;
	}

  // populate base list
	var list = [];
	function getSeedNumber() { return Math.random()*100; }
	for(var i = 0; i < 50; i++) list.push( getSeedNumber() );

  // our calculation functions, for comparison
	function calcNormalAvg(list) {
  	// sum(list) / len(list)
		return list.reduce(function(a, b) { return a + b; }) / list.length;
	}
	function calcRunningAvg(previousAverage, currentNumber, index) {
  	// [ avg' * (n-1) + x ] / n
		return ( previousAverage * (index - 1) + currentNumber ) / index;
	}
  function calcMovingAvg(accumulator, new_value, alpha) {
  	return (alpha * new_value) + (1.0 - alpha) * accumulator;
	}
	
  // start our baseline
	var baseAvg = calcNormalAvg(list);
	var runningAvg = baseAvg, movingAvg = baseAvg;
	log('base avg: %d', baseAvg);
  
  var okay = true;
  
  // table of output, cleaner console view
  var results = [];
	
  // add 10 more numbers to the list and compare calculations
	for(var n = list.length, i = 0; i < 10; i++, n++) {
		var newNumber = getSeedNumber();
    
		runningAvg = calcRunningAvg(runningAvg, newNumber, n+1);
    movingAvg = calcMovingAvg(movingAvg, newNumber, 1/(n+1));

		list.push(newNumber);
		baseAvg = calcNormalAvg(list);

		// assert and inspect
		log('added [%d] to list at pos %d, running avg = %d vs. regular avg = %d (%s)'
			, newNumber, list.length, runningAvg, baseAvg, runningAvg == baseAvg
		)
    results.push( {x: newNumber, n:list.length, regular: baseAvg, running: runningAvg, moving: movingAvg, eqRun: baseAvg == runningAvg, eqMov: baseAvg == movingAvg } );
    
   ...