Averages/Simple moving average: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|J}}: link to lexical closure J FAQ)
Line 264: Line 264:
=={{header|J}}==
=={{header|J}}==


'''Note''': J is block-oriented, not stream oriented. That is, J expresses algorithms under the assumption that all the data is available at once (rather than maintaining state and waiting for the next item).
'''Note''': J is block-oriented, not stream oriented. That is, J expresses algorithms with the semantics that all the data is available at once (rather than maintaining state and waiting for the next item).


In that context, moving average is expressed very concisely in J as '''<tt>(+/%#)\</tt>'''.
In that context, moving average is expressed very concisely in J as '''<tt>(+/%#)\</tt>'''.

Revision as of 16:03, 6 August 2009

Task
Averages/Simple moving average
You are encouraged to solve this task according to the task description, using any language you may know.

Computing the simple moving average of a series of numbers.

Create a stateful function/class/instance that takes a number as argument and returns a simple moving average of its arguments so far.

See also: Standard Deviation

AutoHotkey

ahk forum: discussion For Integers: <lang AutoHotkey>MsgBox % MovingAverage(5,3)  ; 5, averaging length <- 3 MsgBox % MovingAverage(1)  ; 3 MsgBox % MovingAverage(-3)  ; 1 MsgBox % MovingAverage(8)  ; 2 MsgBox % MovingAverage(7)  ; 4

MovingAverage(x,len="") {  ; for integers (faster)

 Static
 Static sum:=0, n:=0, m:=10 ; default averaging length = 10
 If (len>"")                ; non-blank 2nd parameter: set length, reset
    sum := n := i := 0, m := len
 If (n < m)                 ; until the buffer is not full
    sum += x, n++           ;   keep summing data
 Else                       ; when buffer is full
    sum += x-v%i%           ;   add new, subtract oldest
 v%i% := x, i := mod(i+1,m) ; remember last m inputs, cycle insertion point
 Return sum/n

}</lang> For floating point numbers: <lang AutoHotkey> MovingAverage(x,len="") {  ; for floating point numbers

 Static
 Static n:=0, m:=10         ; default averaging length = 10
 If (len>"")                ; non-blank 2nd parameter: set length, reset
    n := i := 0, m := len
 n += n < m, sum := 0
 v%i% := x, i := mod(i+1,m) ; remember last m inputs, cycle insertion point
 Loop %n%                   ; recompute sum to avoid error accumulation
    j := A_Index-1, sum += v%j%
 Return sum/n

}</lang>

C

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <stdarg.h>

typedef struct sma_obj {

 double sma;
 double sum;
 int period;
 double *values;
 int lv;

} sma_obj_t;

typedef union sma_result {

 sma_obj_t *handle;
 double sma;
 double *values;

} sma_result_t;

enum Action { SMA_NEW, SMA_FREE, SMA_VALUES, SMA_ADD, SMA_MEAN }; sma_result_t sma(enum Action action, ...) {

 va_list vl;
 sma_result_t r;
 sma_obj_t *o;
 double v;
 va_start(vl, action);
 switch(action) {
 case SMA_NEW: // args: int period
   r.handle = malloc(sizeof(sma_obj_t));
   r.handle->sma = 0.0;
   r.handle->period = va_arg(vl, int);
   r.handle->values = malloc(r.handle->period * sizeof(double));
   r.handle->lv = 0;
   r.handle->sum = 0.0;
   break;
 case SMA_FREE: // args: sma_obj_t *handle
   r.handle = va_arg(vl, sma_obj_t *);
   free(r.handle->values);
   free(r.handle);
   r.handle = NULL;
   break;
 case SMA_VALUES: // args: sma_obj_t *handle
   o = va_arg(vl, sma_obj_t *);
   r.values = o->values;
   break;
 case SMA_MEAN: // args: sma_obj_t *handle
   o = va_arg(vl, sma_obj_t *);
   r.sma = o->sma;
   break;
 case SMA_ADD: // args: sma_obj_t *handle, double value
   o = va_arg(vl, sma_obj_t *);
   v = va_arg(vl, double);
   if ( o->lv < o->period ) {
     o->values[o->lv++] = v;
     o->sum += v;
     o->sma = o->sum / o->lv;
   } else {
     o->sum -= o->values[ o->lv % o->period];
     o->sum += v;
     o->sma = o->sum / o->period;
     o->values[ o->lv % o->period ] = v; o->lv++;
   }
   r.sma = o->sma;
   break;
 }
 va_end(vl);
 return r;

}</lang>

<lang c>double v[] = { 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 };

int main() {

 int i;
 sma_obj_t *h3 = sma(SMA_NEW, 3).handle;
 sma_obj_t *h5 = sma(SMA_NEW, 5).handle;
 for(i=0; i < sizeof(v)/sizeof(double) ; i++) {
   printf("next number %lf, SMA_3 = %lf, SMA_5 = %lf\n",

v[i], sma(SMA_ADD, h3, v[i]).sma, sma(SMA_ADD, h5, v[i]).sma);

 }
 sma(SMA_FREE, h3);
 sma(SMA_FREE, h5);
 return 0;

}</lang>

Common Lisp

This implementation uses a circular list to store the numbers within the window; at the beginning of each iteration pointer refers to the list cell which holds the value just moving out of the window and to be replaced with the just-added value.

<lang lisp>(defun simple-moving-average (period &aux

   (sum 0) (count 0) (values (make-list period)) (pointer values))
 (setf (rest (last values)) values)  ; construct circularity
 (lambda (n)
   (when (first pointer)
     (decf sum (first pointer)))     ; subtract old value
   (incf sum n)                      ; add new value
   (incf count)
   (setf (first pointer) n)
   (setf pointer (rest pointer))     ; advance pointer
   (/ sum (min count period))))</lang>

E

This implementation produces two (function) objects sharing state. It is idiomatic in E to separate input from output (read from write) rather than combining them into one object.

The structure is the same as the implementation of Standard Deviation#E.

<lang e>pragma.enable("accumulator") def makeMovingAverage(period) {

   def values := ([null] * period).diverge()
   var index := 0
   var count := 0
   
   def insert(v) {
       values[index] := v
       index := (index + 1) %% period
       count += 1
   }
   
   /** Returns the simple moving average of the inputs so far, or null if there
       have been no inputs. */
   def average() {
       if (count > 0) {
           return accum 0 for x :notNull in values { _ + x } / count.min(period)
       }
   }
   
   return [insert, average]

}</lang>

<lang e>? for period in [3, 5] { > def [insert, average] := makeMovingAverage(period) > println(`Period $period:`) > for value in [1,2,3,4,5,5,4,3,2,1] { > insert(value) > println(value, "\t", average()) > } > println() > } 0.0 1.0 0.9428090415820626 0.8660254037844386 0.9797958971132716 1.0 1.3997084244475297 2.0</lang>

Forth

<lang forth>

f+! ( f addr -- ) dup f@ f+ f! ;
,f0s ( n -- ) falign 0 do 0e f, loop ;
period @ ;
used cell+ ;
head 2 cells + ;
sum 3 cells + faligned ;
ring ( addr -- faddr )
 dup sum float+ swap head @ floats + ;
update ( fvalue addr -- addr )
      dup ring f@ fnegate dup sum f+!
 fdup dup ring f!         dup sum f+!
 dup head @ 1+  over period mod  over head ! ;
moving-average
 create ( period -- ) dup , 0 , 0 , 1+ ,f0s
 does>  ( fvalue -- avg )
   update
   dup used @ over period < if 1 over used +! then
   dup sum f@ used @ 0 d>f f/ ;

3 moving-average sma 1e sma f. \ 1. 2e sma f. \ 1.5 3e sma f. \ 2. 4e sma f. \ 3. </lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>program Movavg

 implicit none
 integer :: i
 write (*, "(a)") "SIMPLE MOVING AVERAGE: PERIOD = 3"
 do i = 1, 5
   write (*, "(a, i2, a, f8.6)") "Next number:", i, "   sma = ", sma(real(i))
 end do
 do i = 5, 1, -1
   write (*, "(a, i2, a, f8.6)") "Next number:", i, "   sma = ", sma(real(i))
 end do 

contains

function sma(n)

 real :: sma
 real, intent(in) :: n
 real, save :: a(3) = 0
 integer, save :: count = 0
 if (count < 3) then
   count = count + 1
   a(count) = n
 else
   a = eoshift(a, 1, n)
 end if
 sma = sum(a(1:count)) / real(count)

end function

end program Movavg </lang>

J

Note: J is block-oriented, not stream oriented. That is, J expresses algorithms with the semantics that all the data is available at once (rather than maintaining state and waiting for the next item).

In that context, moving average is expressed very concisely in J as (+/%#)\.

In the context of the task, we need to produce a stateful function to consume streams. Since J does not have native lexical closure, we need to implement it. Thus the streaming solution is more complex:

   lex =:  1 :'(a[n__a=.m#_.[a=.18!:3$~0)&(4 :''(+/%#)(#~1-128!:5)n__x=.1|.!.y n__x'')'

an example:

   sma =: 5 lex
   sma&> 1 2 3 4 5 5 4 3 2 1
1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3

Here, the &> is analogous to the "for each" of other languages.

Java

Works with: Java version 1.5+

<lang java5>import java.util.LinkedList; public class MovingAverage {

   LinkedList<Double> window;
   private int size;
   public MovingAverage(int size) {
       window = new LinkedList<Double>();
       this.size = size;
   }
   public static void main(String[] args) {
       double[] testData = {1,2,3,4,5,5,4,3,2,1};
       int[] windowSizes = {3,5};
       for(int windSize : windowSizes){
           MovingAverage ma = new MovingAverage(windSize);
           for (double x : testData) {
               ma.newNum(x);
               System.out.println(ma.getAvg());
           }
           System.out.println();
       }
   }
   public void newNum(double num) {
       window.add(num);
       if (window.size() > size) {
           window.removeFirst();
       }
   }
   public double getAvg() {
       if (window.isEmpty()) return 0;
       double ret = 0;
       double sum = 0;
       for (double num : window) {
          sum += num;
       }
       return sum / Math.min(window.size(), size);
   }

}</lang> Output:

1.0
1.5
2.0
3.0
4.0
4.666666666666667
4.666666666666667
4.0
3.0
2.0

1.0
1.5
2.0
2.5
3.0
3.8
4.2
4.2
3.8
3.0

Perl

<lang perl>sub sma ($)

{my ($period, $sum, @a) = shift, 0;
 return sub
    {unshift @a, shift;
     $sum += $a[0];
     @a > $period and $sum -= pop @a;
     return $sum / @a;}}</lang>

Python

Works with: Python version 3.x

<lang python>def simplemovingaverage(period):

   assert period == int(period) and period > 0, "Period must be an integer >0"
   
   summ = n = 0.0
   values = [0.0] * period     # old value queue
   def sma(x):
       nonlocal summ, n, values
       
       n += 1
       values.insert(0, x)
       summ += x - values.pop()
       n = n if n <= period else period
       return summ / n
   return sma


if __name__ == '__main__':

   for period in [3, 5]:
       print ("\nSIMPLE MOVING AVERAGE: PERIOD =", period)
       sma = simplemovingaverage(period)
       for i in range(1,6):
           print ("  Next number = %-2g, SMA = %g " % (i, sma(i)))
       for i in range(5, 0, -1):
           print ("  Next number = %-2g, SMA = %g " % (i, sma(i)))</lang>

Sample output

SIMPLE MOVING AVERAGE: PERIOD = 3
  Next number = 1 , SMA = 1 
  Next number = 2 , SMA = 1.5 
  Next number = 3 , SMA = 2 
  Next number = 4 , SMA = 3 
  Next number = 5 , SMA = 4 
  Next number = 5 , SMA = 4.66667 
  Next number = 4 , SMA = 4.66667 
  Next number = 3 , SMA = 4 
  Next number = 2 , SMA = 3 
  Next number = 1 , SMA = 2 

SIMPLE MOVING AVERAGE: PERIOD = 5
  Next number = 1 , SMA = 1 
  Next number = 2 , SMA = 1.5 
  Next number = 3 , SMA = 2 
  Next number = 4 , SMA = 2.5 
  Next number = 5 , SMA = 3 
  Next number = 5 , SMA = 3.8 
  Next number = 4 , SMA = 4.2 
  Next number = 3 , SMA = 4.2 
  Next number = 2 , SMA = 3.8 
  Next number = 1 , SMA = 3 

R

This is easiest done with two functions: one to handle the state (i.e. the numbers already entered), and one to calculate the average. <lang R>

  1. concat concatenates the new values to the existing vector of values, then discards any values that are too old.

lastvalues <- local( {

  values <- c(); 
  function(x, len)
  {
     values <<- c(values, x); 
     lenv <- length(values); 
     if(lenv > len) values <<- values[(len-lenv):-1]
     values
  }

})

  1. moving.average accepts a numeric scalars input (and optionally a length, i.e. the number of values to retain) and calculates the stateful moving average.

moving.average <- function(latestvalue, len=3) {

  #Check that all inputs are numeric scalars
  is.numeric.scalar <- function(x) is.numeric(x) && length(x)==1L
  if(!is.numeric.scalar(latestvalue) || !is.numeric.scalar(len))
  {
     stop("all arguments must be numeric scalars")
  }
  
  #Calculate mean of variables so far  
  mean(lastvalues(latestvalue, len))

} moving.average(5) # 5 moving.average(1) # 3 moving.average(-3) # 1 moving.average(8) # 2 moving.average(7) # 4 </lang>

Ruby

A closure: <lang ruby>def simple_moving_average(size)

 nums = []
 sum = 0.0
 lambda do |hello|
   nums << hello
   goodbye = nums.length > size ? nums.shift : 0
   sum += hello - goodbye
   sum / nums.length
 end

end

ma3 = simple_moving_average(3) ma5 = simple_moving_average(5)

(1.upto(5).to_a + 5.downto(1).to_a).each do |num|

 printf "Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n", 
   num, ma3.call(num), ma5.call(num)

end</lang>

A class <lang ruby>class MovingAverager

 def initialize(size)
   @size = size
   @nums = []
   @sum = 0.0
 end
 def <<(hello)
   @nums << hello
   goodbye = @nums.length > @size ? @nums.shift : 0
   @sum += hello - goodbye
   self
 end
 def average
   @sum / @nums.length
 end
 alias to_f average
 def to_s
   average.to_s
 end

end

ma3 = MovingAverager.new(3) ma5 = MovingAverager.new(5)

(1.upto(5).to_a + 5.downto(1).to_a).each do |num|

 printf "Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n", 
   num, ma3 << num, ma5 <<num

end</lang>

Smalltalk

Works with: GNU Smalltalk

<lang smalltalk>Object subclass: MovingAverage [

   |valueCollection period collectedNumber sum|
   MovingAverage class >> newWithPeriod: thePeriod [

|r| r := super basicNew. ^ r initWithPeriod: thePeriod

   ]
   initWithPeriod: thePeriod [
   	valueCollection := OrderedCollection new: thePeriod.

period := thePeriod. collectedNumber := 0. sum := 0

   ]
   sma [   collectedNumber < period
           ifTrue: [ ^ sum / collectedNumber ]
           ifFalse: [ ^ sum / period ] ]
   add: value [
       collectedNumber < period
  	ifTrue: [

sum := sum + value. valueCollection add: value. collectedNumber := collectedNumber + 1. ] ifFalse: [ sum := sum - (valueCollection removeFirst). sum := sum + value. valueCollection add: value ]. ^ self sma

   ]

].</lang>

<lang smalltalk>|sma3 sma5|

sma3 := MovingAverage newWithPeriod: 3. sma5 := MovingAverage newWithPeriod: 5.

  1. ( 1 2 3 4 5 5 4 3 2 1 ) do: [ :v |
 ('Next number %1, SMA_3 = %2, SMA_5 = %3' % {
        v . (sma3 add: v) asFloat . (sma5 add: v) asFloat
   }) displayNl

]</lang>

Tcl

Works with: Tcl version 8.6

<lang tcl>oo::class create SimpleMovingAverage {

   variable vals idx
   constructor Template:Period 3 {
       set idx end-[expr {$period-1}]
       set vals {}
   }
   method val x {
       set vals [lrange [list {*}$vals $x] $idx end]
       expr {[tcl::mathop::+ {*}$vals]/double([llength $vals])}
   }

}</lang> Demonstration: <lang tcl>SimpleMovingAverage create averager3 SimpleMovingAverage create averager5 5 foreach n {1 2 3 4 5 5 4 3 2 1} {

   puts "Next number = $n, SMA_3 = [averager3 val $n], SMA_5 = [averager5 val $n]"

}</lang> Output:

Next number = 1, SMA_3 = 1.0, SMA_5 = 1.0
Next number = 2, SMA_3 = 1.5, SMA_5 = 1.5
Next number = 3, SMA_3 = 2.0, SMA_5 = 2.0
Next number = 4, SMA_3 = 3.0, SMA_5 = 2.5
Next number = 5, SMA_3 = 4.0, SMA_5 = 3.0
Next number = 5, SMA_3 = 4.666666666666667, SMA_5 = 3.8
Next number = 4, SMA_3 = 4.666666666666667, SMA_5 = 4.2
Next number = 3, SMA_3 = 4.0, SMA_5 = 4.2
Next number = 2, SMA_3 = 3.0, SMA_5 = 3.8
Next number = 1, SMA_3 = 2.0, SMA_5 = 3.0