Movatterモバイル変換


[0]ホーム

URL:


Jump to content
Rosetta Code
Search

Averages/Simple moving average

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

Computing thesimple moving average of a series of numbers.

Task

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

Description


A simple moving average is a method for computing an average of a stream of numbers by only averaging the last   P   numbers from the stream,   where   P   is known as the period.

It can be implemented by calling an initialing routine with   P   as its argument,   I(P),   which should then return a routine that when called with individual, successive members of a stream of numbers, computes the mean of (up to), the last   P   of them, lets call this   SMA().

The word  stateful   in the task description refers to the need for   SMA()   to remember certain information between calls to it:

  •   The period,   P
  •   An ordered container of at least the last   P   numbers from each of its individual calls.


Stateful   also means that successive calls to   I(),   the initializer,   should return separate routines that do  not   share saved state so they could be used on two independent streams of data.

Pseudo-code for an implementation of   SMA   is:

function SMA(number: N):    stateful integer: P    stateful list:    stream    number:           average    stream.append_last(N)    if stream.length() > P:        # Only average the last P elements of the stream        stream.delete_first()    if stream.length() == 0:        average = 0    else:            average = sum( stream.values() ) / stream.length()    return average
See also


Tasks for calculating statistical measures

11l

Translation of:D
T SMA   [Float] data   sum = 0.0   index = 0   n_filled = 0   Int period   F (period)      .period = period      .data = [0.0] * period   F add(v)      .sum += v - .data[.index]      .data[.index] = v      .index = (.index + 1) % .period      .n_filled = min(.period, .n_filled + 1)      R .sum / .n_filledV sma3 = SMA(3)V sma5 = SMA(5)L(e) [1, 2, 3, 4, 5, 5, 4, 3, 2, 1]   print(‘Added #., sma(3) = #.6, sma(5) = #.6’.format(e, sma3.add(e), sma5.add(e)))
Output:
Added 1, sma(3) = 1.000000, sma(5) = 1.000000Added 2, sma(3) = 1.500000, sma(5) = 1.500000Added 3, sma(3) = 2.000000, sma(5) = 2.000000Added 4, sma(3) = 3.000000, sma(5) = 2.500000Added 5, sma(3) = 4.000000, sma(5) = 3.000000Added 5, sma(3) = 4.666667, sma(5) = 3.800000Added 4, sma(3) = 4.666667, sma(5) = 4.200000Added 3, sma(3) = 4.000000, sma(5) = 4.200000Added 2, sma(3) = 3.000000, sma(5) = 3.800000Added 1, sma(3) = 2.000000, sma(5) = 3.000000

360 Assembly

Translation of:PL/I
*        Averages/Simple moving average  26/08/2015AVGSMA   CSECT         USING  AVGSMA,R12         LR     R12,R15         ST     R14,SAVER14         ZAP    II,=P'0'           ii=0         LA     R7,1         LH     R3,NA         SRA    R3,1               na/2LOOPA    CR     R7,R3              do i=1 to na/2         BH     ELOOPA         AP     II,=P'1000'        ii=ii+1000         LR     R1,R7              i         MH     R1,=H'6'         LA     R4,A-6(R1)         MVC    0(6,R4),II         a(i)=ii         LH     R1,NA              na         SR     R1,R7              -i         MH     R1,=H'6'         LA     R4,A(R1)         MVC    0(6,R4),II         a(na+1-i)=ii         LA     R7,1(R7)         B      LOOPAELOOPA   XPRNT  =CL30' n     sma3        sma5       ',30         XPRNT  =CL30' ----- ----------- -----------',30         LA     R7,1               i=1LOOP     CH     R7,NA              do i=1 to na         BH     RETURN         STH    R7,N               n=i         XDECO  R7,C               i         MVC    BUF+1(5),C+7         MVC    P,=H'3'            p=3         BAL    R14,SMA         MVC    C(13),EDMASK         ED     C(13),SS           sma(3,i)         MVC    BUF+7(11),C+2         MVC    P,=H'5'            p=5         BAL    R14,SMA         MVC    C(13),EDMASK         ED     C(13),SS           sma(5,i)         MVC    BUF+19(11),C+2         XPRNT  BUF,30             output i,sma3,sma5         LA     R7,1(R7)         B      LOOP*        *****  sub sma(p,n) returns(PL6)SMA      LH     R5,N         SH     R5,P         A      R5,=F'1'           ia=n-p+1         C      R5,=F'1'         BH     OKIA         LA     R5,1               ia=1OKIA     LH     R6,NA              ib=na         CH     R6,N         BL     OKIB         LH     R6,N               ib=nOKIB     ZAP    II,=P'0'           ii=0         ZAP    SS,=P'0'           ss=0         LR     R3,R5              k=iaLOOPK    CR     R3,R6              do k=ia to ib         BH     ELOOPK         AP     II,=P'1'           ii=ii+1         LR     R1,R3         MH     R1,=H'6'         LA     R4,A-6(R1)         MVC    C(6),0(R4)         ss=ss+a(k)         AP     SS,C(6)         LA     R3,1(R3)         B      LOOPKELOOPK   ZAP    C,SS         DP     C,II         ZAP    SS,C(10)           ss=ss/ii         BR     R14RETURN   L      R14,SAVER14        restore caller address         XR     R15,R15         BR     R14SAVER14  DS     FNN       EQU    10NA       DC     AL2(NN)A        DS     (NN)PL6II       DS     PL6SS       DS     PL6P        DS     HN        DS     HC        DS     CL16BUF      DC     CL30'                              '  bufferEDMASK   DC     X'4020202020202021204B202020'  CL13         YREGS         END    AVGSMA
Output:
 n     sma3        sma5 ----- ----------- -----------     1       1.000       1.000     2       1.500       1.500     3       2.000       2.000     4       3.000       2.500     5       4.000       3.000     6       4.666       3.800     7       4.666       4.200     8       4.000       4.200     9       3.000       3.800    10       2.000       3.000

Ada

Works with:Ada 2005

moving.ads:

genericMax_Elements:Positive;typeNumberisdigits<>;packageMovingisprocedureAdd_Number(N:Number);functionMoving_Average(N:Number)returnNumber;functionGet_AveragereturnNumber;endMoving;

moving.adb:

withAda.Containers.Vectors;packagebodyMovingisuseAda.Containers;packageNumber_Vectorsis newAda.Containers.Vectors(Element_Type=> Number,Index_Type=> Natural);Current_List:Number_Vectors.Vector:=Number_Vectors.Empty_Vector;procedureAdd_Number(N:Number)isbeginifNatural(Current_List.Length)>=Max_ElementsthenCurrent_List.Delete_First;endif;Current_List.Append(N);endAdd_Number;functionGet_AveragereturnNumberisAverage:Number:=0.0;procedureSum(Position:Number_Vectors.Cursor)isbeginAverage:=Average+Number_Vectors.Element(Position);endSum;beginCurrent_List.Iterate(Sum'Access);ifCurrent_List.Length>1thenAverage:=Average/Number(Current_List.Length);endif;returnAverage;endGet_Average;functionMoving_Average(N:Number)returnNumberisbeginAdd_Number(N);returnGet_Average;endMoving_Average;endMoving;

main.adb:

withAda.Text_IO;withMoving;procedureMainispackageThree_Averageis newMoving(Max_Elements=> 3,Number=> Float);packageFive_Averageis newMoving(Max_Elements=> 5,Number=> Float);beginforIin1..5loopAda.Text_IO.Put_Line("Inserting"&Integer'Image(I)&" into max-3: "&Float'Image(Three_Average.Moving_Average(Float(I))));Ada.Text_IO.Put_Line("Inserting"&Integer'Image(I)&" into max-5: "&Float'Image(Five_Average.Moving_Average(Float(I))));endloop;forIinreverse1..5loopAda.Text_IO.Put_Line("Inserting"&Integer'Image(I)&" into max-3: "&Float'Image(Three_Average.Moving_Average(Float(I))));Ada.Text_IO.Put_Line("Inserting"&Integer'Image(I)&" into max-5: "&Float'Image(Five_Average.Moving_Average(Float(I))));endloop;endMain;
Output:
Inserting 1 into max-3:  1.00000E+00Inserting 1 into max-5:  1.00000E+00Inserting 2 into max-3:  1.50000E+00Inserting 2 into max-5:  1.50000E+00Inserting 3 into max-3:  2.00000E+00Inserting 3 into max-5:  2.00000E+00Inserting 4 into max-3:  3.00000E+00Inserting 4 into max-5:  2.50000E+00Inserting 5 into max-3:  4.00000E+00Inserting 5 into max-5:  3.00000E+00Inserting 5 into max-3:  4.66667E+00Inserting 5 into max-5:  3.80000E+00Inserting 4 into max-3:  4.66667E+00Inserting 4 into max-5:  4.20000E+00Inserting 3 into max-3:  4.00000E+00Inserting 3 into max-5:  4.20000E+00Inserting 2 into max-3:  3.00000E+00Inserting 2 into max-5:  3.80000E+00Inserting 1 into max-3:  2.00000E+00Inserting 1 into max-5:  3.00000E+00

ALGOL 68

Translation of:C
Works with:ALGOL 68 version Standard - no extensions to language used
Works with:ALGOL 68G version Any - tested with release1.18.0-9h.tiny

Note: This following code is a direct translation of theC code sample. It mimics C's var_list implementation, and so it probably isn't the most natural way of dong this actual task inALGOL 68.

MODE SMAOBJ  = STRUCT(  LONG REAL sma,  LONG REAL sum,  INT period,  REF[]LONG REAL values,  INT lv); MODE SMARESULT = UNION (  REF SMAOBJ # handle #,  LONG REAL # sma #,  REF[]LONG REAL # values #); MODE SMANEW = INT,     SMAFREE = STRUCT(REF SMAOBJ free obj),     SMAVALUES = STRUCT(REF SMAOBJ values obj),     SMAADD = STRUCT(REF SMAOBJ add obj, LONG REAL v),     SMAMEAN = STRUCT(REF SMAOBJ mean obj, REF[]LONG REAL v);MODE ACTION = UNION ( SMANEW, SMAFREE, SMAVALUES, SMAADD, SMAMEAN );PROC sma = ([]ACTION action)SMARESULT:(  SMARESULT result;  REF SMAOBJ obj;  LONG REAL v;  FOR i FROM LWB action TO UPB action DO    CASE action[i] IN    (SMANEW period):( # args: INT period #       HEAP SMAOBJ handle;       sma OF handle := 0.0;       period OF handle := period;       values OF handle := HEAP [period OF handle]LONG REAL;       lv OF handle := 0;       sum OF handle := 0.0;       result := handle    ),    (SMAFREE args):( # args: REF SMAOBJ free obj #       free obj OF args := REF SMAOBJ(NIL) # let the garbage collector do it's job #    ),    (SMAVALUES args):( # args: REF SMAOBJ values obj #       result := values OF values obj OF args    ),    (SMAMEAN args):( # args: REF SMAOBJ mean obj #       result := sma OF mean obj OF args    ),    (SMAADD args):( # args: REF SMAOBJ add obj, LONG REAL v #       obj := add obj OF args;       v := v OF args;       IF lv OF obj < period OF obj THEN         (values OF obj)[lv OF obj+:=1] := v;         sum OF obj +:= v;         sma OF obj := sum OF obj / lv OF obj       ELSE         sum OF obj -:= (values OF obj)[ 1+ lv OF obj MOD period OF obj];         sum OF obj +:= v;         sma OF obj := sum OF obj / period OF obj;         (values OF obj)[ 1+ lv OF obj  MOD  period OF obj ] := v; lv OF obj+:=1       FI;       result := sma OF obj    )    OUT      SKIP    ESAC  OD;  result);[]LONG REAL v = ( 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 ); main: (  INT i;   REF SMAOBJ h3 := ( sma(SMANEW(3)) | (REF SMAOBJ obj):obj );  REF SMAOBJ h5 := ( sma(SMANEW(5)) | (REF SMAOBJ obj):obj );   FOR i FROM LWB v TO UPB v DO    printf(($"next number "g(0,6)", SMA_3 = "g(0,6)", SMA_5 = "g(0,6)l$,           v[i], (sma(SMAADD(h3, v[i]))|(LONG REAL r):r), ( sma(SMAADD(h5, v[i])) | (LONG REAL r):r )    ))  OD#;   sma(SMAFREE(h3));  sma(SMAFREE(h5))#)
Output:
next number 1.000000, SMA_3 = 1.000000, SMA_5 = 1.000000next number 2.000000, SMA_3 = 1.500000, SMA_5 = 1.500000next number 3.000000, SMA_3 = 2.000000, SMA_5 = 2.000000next number 4.000000, SMA_3 = 3.000000, SMA_5 = 2.500000next number 5.000000, SMA_3 = 4.000000, SMA_5 = 3.000000next number 5.000000, SMA_3 = 4.666667, SMA_5 = 3.800000next number 4.000000, SMA_3 = 4.666667, SMA_5 = 4.200000next number 3.000000, SMA_3 = 4.000000, SMA_5 = 4.200000next number 2.000000, SMA_3 = 3.000000, SMA_5 = 3.800000next number 1.000000, SMA_3 = 2.000000, SMA_5 = 3.000000

AutoHotkey

ahk forum:discussionFor Integers:

MsgBox%MovingAverage(5,3)  ; 5, averaging length <- 3MsgBox%MovingAverage(1)    ; 3MsgBox%MovingAverage(-3)   ; 1MsgBox%MovingAverage(8)    ; 2MsgBox%MovingAverage(7)    ; 4MovingAverage(x,len=""){    ; for integers (faster)StaticStaticsum:=0,n:=0,m:=10 ; default averaging length = 10If(len>"")                ; non-blank 2nd parameter: set length, resetsum:=n:=i:=0,m:=lenIf(n<m)                 ; until the buffer is not fullsum+=x,n++           ;   keep summing dataElse                       ; when buffer is fullsum+=x-v%i%           ;   add new, subtract oldestv%i%:=x,i:=mod(i+1,m) ; remember last m inputs, cycle insertion pointReturnsum/n}

For floating point numbers:

MovingAverage(x,len=""){    ; for floating point numbersStaticStaticn:=0,m:=10         ; default averaging length = 10If(len>"")                ; non-blank 2nd parameter: set length, resetn:=i:=0,m:=lenn+=n<m,sum:=0v%i%:=x,i:=mod(i+1,m) ; remember last m inputs, cycle insertion pointLoop%n%                   ; recompute sum to avoid error accumulationj:=A_Index-1,sum+=v%j%Returnsum/n}

AWK

#!/usr/bin/awk -f# Moving average over the first column of a data fileBEGIN{P=5;}{x=$1;i=NR%P;MA+=(x-Z[i])/P;Z[i]=x;printMA;}

Ballerina

Translation of:Go
importballerina/io;functionsma(intperiod)returns(function(float)returnsfloat){inti=0;floatsum=0.0;float[]storage=[];returnfunction(floatinput)returnsfloat{ifstorage.length()<period{sum+=input;storage.push(input);}sum+=input-storage[i];storage[i]=input;i=(i+1)%period;returnsum/<float>storage.length();};}functionF(floatf,intsize,intprec)returnsstring{strings=f.toFixedString(prec);returnsize>=0?s.padStart(size):s.padEnd(size);}publicfunctionmain(){varsma3=sma(3);varsma5=sma(5);io:println(" x      sma3   sma5");float[]rng=[1,2,3,4,5,5,4,3,2,1];foreachfloatxinrng{io:println(`${F(x, 5, 3)}  ${F(sma3(x), 5, 3)}  ${F(sma5(x), 5, 3)}`);}}
Output:
 x      sma3   sma51.000  1.000  1.0002.000  1.500  1.5003.000  2.000  2.0004.000  3.000  2.5005.000  4.000  3.0005.000  4.667  3.8004.000  4.667  4.2003.000  4.000  4.2002.000  3.000  3.8001.000  2.000  3.000

BBC BASIC

Works with:BBC BASIC for Windows
MAXPERIOD=10FORn=1TO5PRINT"Number = ";nTAB(12)" SMA3 = ";FNsma(n,3)TAB(30)" SMA5 = ";FNsma(n,5)NEXTFORn=5TO1STEP-1PRINT"Number = ";nTAB(12)" SMA3 = ";FNsma(n,3)TAB(30)" SMA5 = ";FNsma(n,5)NEXTENDDEFFNsma(number,period%)PRIVATEnums(),accum(),index%(),window%()DIMnums(MAXPERIOD,MAXPERIOD),accum(MAXPERIOD)DIMindex%(MAXPERIOD),window%(MAXPERIOD)accum(period%)+=number-nums(period%,index%(period%))nums(period%,index%(period%))=numberindex%(period%)=(index%(period%)+1)MODperiod%IFwindow%(period%)<period%window%(period%)+=1=accum(period%)/window%(period%)
Output:
Number = 1   SMA3 = 1          SMA5 = 1Number = 2   SMA3 = 1.5        SMA5 = 1.5Number = 3   SMA3 = 2          SMA5 = 2Number = 4   SMA3 = 3          SMA5 = 2.5Number = 5   SMA3 = 4          SMA5 = 3Number = 5   SMA3 = 4.66666667 SMA5 = 3.8Number = 4   SMA3 = 4.66666667 SMA5 = 4.2Number = 3   SMA3 = 4          SMA5 = 4.2Number = 2   SMA3 = 3          SMA5 = 3.8Number = 1   SMA3 = 2          SMA5 = 3

BQN

SMA takes moving average of a list, given the whole array.

SMA2 returns a stateful function which can be run on individual numbers of a stream.

SMA ← {(+´÷≠)¨(1↓𝕨↑↑𝕩)∾<˘𝕨↕𝕩}v ← (⊢∾⌽)1+↕5•Show 5 SMA vSMA2 ← {  𝕊 size:  nums ← ⟨⟩  sum ← 0  {    nums ∾↩ 𝕩     gb ← {(≠nums)≤size ? 0 ; a←⊑nums, nums↩1↓nums, a}    sum +↩ 𝕩 - gb    sum ÷ ≠nums  }}fun ← SMA2 5Fun¨ v
⟨ 1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3 ⟩⟨ 1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3 ⟩

Try It!

Bracmat

( ( I  =   buffer    .   (new$=):?freshEmptyBuffer      &        ' ( buffer avg          .   ( avg              =   L S n                .   0:?L:?S                  &   whl                    ' ( !arg:%?n ?arg                      & !n+!S:?S                      & 1+!L:?L                      )                  & (!L:0&0|!S*!L^-1)              )            & (buffer=$freshEmptyBuffer)            & !arg !(buffer.):?(buffer.)            & ( !(buffer.):?(buffer.) [($arg) ?              |              )            & avg$!(buffer.)          )  )& ( pad  =   len w    .   @(!arg:? [?len)      & @("     ":? [!len ?w)      & !w !arg  )& I$3:(=?sma3)& I$5:(=?sma5)& 1 2 3 4 5 5 4 3 2 1:?K&   whl  ' ( !K:%?k ?K    &   out      $ (str$(!k " - sma3:" pad$(sma3$!k) "  sma5:" pad$(sma5$!k)))    ));
Output:
1 - sma3:    1  sma5:    12 - sma3:  3/2  sma5:  3/23 - sma3:    2  sma5:    24 - sma3:    3  sma5:  5/25 - sma3:    4  sma5:    35 - sma3: 14/3  sma5: 19/54 - sma3: 14/3  sma5: 21/53 - sma3:    4  sma5: 21/52 - sma3:    3  sma5: 19/51 - sma3:    2  sma5:    3

Brat

Object version

SMA = object.newSMA.init = { period |  my.period = period  my.list = []  my.average = 0}SMA.prototype.add = { num |  true? my.list.length >= my.period    { my.list.deq }  my.list << num  my.average = my.list.reduce(:+) / my.list.length}sma3 = SMA.new 3sma5 = SMA.new 5[1, 2, 3, 4, 5, 5, 4, 3, 2, 1].each { n |  p n, " - SMA3: ", sma3.add(n), " SMA5: ", sma5.add(n)}

Function version

sma = { period |  list = []  { num |    true? list.length >= period      { list.deq }    list << num    list.reduce(:+) / list.length  }}sma3 = sma 3sma5 = sma 5[1, 2, 3, 4, 5, 5, 4, 3, 2, 1].each { n |  p n, " - SMA3: ", sma3(n), " SMA5: ", sma5(n)}
Output:
1 - SMA3: 1 SMA5: 12 - SMA3: 1.5 SMA5: 1.53 - SMA3: 2 SMA5: 24 - SMA3: 3 SMA5: 2.55 - SMA3: 4 SMA5: 35 - SMA3: 4.6666666666667 SMA5: 3.84 - SMA3: 4.6666666666667 SMA5: 4.23 - SMA3: 4 SMA5: 4.22 - SMA3: 3 SMA5: 3.81 - SMA3: 2 SMA5: 3

C

#include<stdio.h>#include<stdlib.h>#include<stdarg.h>typedefstructsma_obj{doublesma;doublesum;intperiod;double*values;intlv;}sma_obj_t;typedefunionsma_result{sma_obj_t*handle;doublesma;double*values;}sma_result_t;enumAction{SMA_NEW,SMA_FREE,SMA_VALUES,SMA_ADD,SMA_MEAN};sma_result_tsma(enumActionaction,...){va_listvl;sma_result_tr;sma_obj_t*o;doublev;va_start(vl,action);switch(action){caseSMA_NEW:// args: int periodr.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;caseSMA_FREE:// args: sma_obj_t *handler.handle=va_arg(vl,sma_obj_t*);free(r.handle->values);free(r.handle);r.handle=NULL;break;caseSMA_VALUES:// args: sma_obj_t *handleo=va_arg(vl,sma_obj_t*);r.values=o->values;break;caseSMA_MEAN:// args: sma_obj_t *handleo=va_arg(vl,sma_obj_t*);r.sma=o->sma;break;caseSMA_ADD:// args: sma_obj_t *handle, double valueo=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);returnr;}
doublev[]={1,2,3,4,5,5,4,3,2,1};intmain(){inti;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);return0;}

C#

Works with:C# version 3
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceSMA{classProgram{staticvoidMain(string[]args){varnums=Enumerable.Range(1,5).Select(n=>(double)n);nums=nums.Concat(nums.Reverse());varsma3=SMA(3);varsma5=SMA(5);foreach(varninnums){Console.WriteLine("{0}    (sma3) {1,-16} (sma5) {2,-16}",n,sma3(n),sma5(n));}}staticFunc<double,double>SMA(intp){Queue<double>s=newQueue<double>(p);return(x)=>{if(s.Count>=p){s.Dequeue();}s.Enqueue(x);returns.Average();};}}}
Output:
1    (sma3) 1                (sma5) 12    (sma3) 1.5              (sma5) 1.53    (sma3) 2                (sma5) 24    (sma3) 3                (sma5) 2.55    (sma3) 4                (sma5) 35    (sma3) 4.66666666666667 (sma5) 3.84    (sma3) 4.66666666666667 (sma5) 4.23    (sma3) 4                (sma5) 4.22    (sma3) 3                (sma5) 3.81    (sma3) 2                (sma5) 3

C++

#include<iostream>#include<stddef.h>#include<assert.h>usingstd::cout;usingstd::endl;classSMA{public:SMA(unsignedintperiod):period(period),window(newdouble[period]),head(NULL),tail(NULL),total(0){assert(period>=1);}~SMA(){delete[]window;}// Adds a value to the average, pushing one out if nescessaryvoidadd(doubleval){// Special case: Initializationif(head==NULL){head=window;*head=val;tail=head;inc(tail);total=val;return;}// Were we already full?if(head==tail){// Fix total-cachetotal-=*head;// Make roominc(head);}// Write the value in the next spot.*tail=val;inc(tail);// Update our total-cachetotal+=val;}// Returns the average of the last P elements added to this SMA.// If no elements have been added yet, returns 0.0doubleavg()const{ptrdiff_tsize=this->size();if(size==0){return0;// No entries => 0 average}returntotal/(double)size;// Cast to double for floating point arithmetic}private:unsignedintperiod;double*window;// Holds the values to calculate the average of.// Logically, head is before taildouble*head;// Points at the oldest element we've stored.double*tail;// Points at the newest element we've stored.doubletotal;// Cache the total so we don't sum everything each time.// Bumps the given pointer up by one.// Wraps to the start of the array if needed.voidinc(double*&p){if(++p>=window+period){p=window;}}// Returns how many numbers we have stored.ptrdiff_tsize()const{if(head==NULL)return0;if(head==tail)returnperiod;return(period+tail-head)%period;}};intmain(intargc,char**argv){SMAfoo(3);SMAbar(5);intdata[]={1,2,3,4,5,5,4,3,2,1};for(int*itr=data;itr<data+10;itr++){foo.add(*itr);cout<<"Added "<<*itr<<" avg: "<<foo.avg()<<endl;}cout<<endl;for(int*itr=data;itr<data+10;itr++){bar.add(*itr);cout<<"Added "<<*itr<<" avg: "<<bar.avg()<<endl;}return0;}

Clojure

This version uses a persistent queue to hold the most recentp values. Each function returned frominit-moving-average has its state in an atom holding a queue value.

(import'[clojure.langPersistentQueue])(defnenqueue-max[qpn](let[q(conjqn)](if(<=(countq)p)q(popq))))(defnavg[coll](/(reduce +coll)(countcoll)))(defninit-moving-avg[p](let[state(atomPersistentQueue/EMPTY)](fn[n](avg(swap!stateenqueue-maxpn)))))

CoffeeScript

I=(P) -># The cryptic name "I" follows the problem description;# it returns a function that computes a moving average# of successive values over the period P, using closure# variables to maintain state.cq=circular_queue(P)num_elems=0sum=0SMA=(n) ->sum+=nifnum_elems<Pcq.add(n)num_elems+=1sum/num_elemselseold=cq.replace(n)sum-=oldsum/Pcircular_queue=(n) -># queue that only ever stores up to n values;# Caller shouldn't call replace until n values# have been added.i=0arr=[]add:(elem) ->arr.pushelemreplace:(elem) -># return value whose age is "n"old_val=arr[i]arr[i]=elemi=(i+1)%nold_val# The output of the code below should convince you that# calling I multiple times returns functions with independent# state.sma3=I(3)sma7=I(7)sma11=I(11)foriin[1..10]console.logi,sma3(i),sma7(i),sma11(i)
Output:
> coffee moving_average.coffee 1 1 1 12 1.5 1.5 1.53 2 2 24 3 2.5 2.55 4 3 36 5 3.5 3.57 6 4 48 7 5 4.59 8 6 510 9 7 5.5

Common Lisp

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

(defunsimple-moving-average(period&aux(sum0)(count0)(values(make-listperiod))(pointervalues))(setf(rest(lastvalues))values); construct circularity(lambda(n)(when(firstpointer)(decfsum(firstpointer))); subtract old value(incfsumn); add new value(incfcount)(setf(firstpointer)n)(setfpointer(restpointer)); advance pointer(/sum(mincountperiod))))

Use

(mapcar'(simple-moving-averageperiod)list-of-values)

Crystal

defsma(n)Proc(Float64,Float64)a=Array(Float64).new->(x:Float64){a.shiftifa.size==na.pushxa.sum/a.size.to_f}endsma3,sma5=sma(3),sma(5)# Copied from the Ruby solution.(1.upto(5).to_a+5.downto(1).to_a).eachdo|n|printf"%d: sma3 = %.3f - sma5 = %.3f\n",n,sma3.call(n.to_f),sma5.call(n.to_f)end
1: sma3 = 1.000 - sma5 = 1.0002: sma3 = 1.500 - sma5 = 1.5003: sma3 = 2.000 - sma5 = 2.0004: sma3 = 3.000 - sma5 = 2.5005: sma3 = 4.000 - sma5 = 3.0005: sma3 = 4.667 - sma5 = 3.8004: sma3 = 4.667 - sma5 = 4.2003: sma3 = 4.000 - sma5 = 4.2002: sma3 = 3.000 - sma5 = 3.8001: sma3 = 2.000 - sma5 = 3.000

D

Using a Closure

Currently thissma can't be @nogc because it allocates a closure on the heap. Some escape analysis could remove the heap allocation.

importstd.stdio,std.traits,std.algorithm;autosma(T,intperiod)()purenothrow@safe{T[period]data=0;Tsum=0;intindex,nFilled;return(inTv)nothrow@safe@nogc{sum+=-data[index]+v;data[index]=v;index=(index+1)%period;nFilled=min(period,nFilled+1);returnCommonType!(T,float)(sum)/nFilled;};}voidmain(){immutables3=sma!(int,3);immutables5=sma!(double,5);foreach(immutablee;[1,2,3,4,5,5,4,3,2,1])writefln("Added %d, sma(3) = %f, sma(5) = %f",e,s3(e),s5(e));}
Output:
Added 1, sma(3) = 1.000000, sma(5) = 1.000000Added 2, sma(3) = 1.500000, sma(5) = 1.500000Added 3, sma(3) = 2.000000, sma(5) = 2.000000Added 4, sma(3) = 3.000000, sma(5) = 2.500000Added 5, sma(3) = 4.000000, sma(5) = 3.000000Added 5, sma(3) = 4.666667, sma(5) = 3.800000Added 4, sma(3) = 4.666667, sma(5) = 4.200000Added 3, sma(3) = 4.000000, sma(5) = 4.200000Added 2, sma(3) = 3.000000, sma(5) = 3.800000Added 1, sma(3) = 2.000000, sma(5) = 3.000000

Using a Struct

This version avoids the heap allocation of the closure keeping the data in the stack frame of the main function. Same output:

importstd.stdio,std.traits,std.algorithm;structSMA(T,intperiod){T[period]data=0;Tsum=0;intindex,nFilled;autoopCall(inTv)purenothrow@safe@nogc{sum+=-data[index]+v;data[index]=v;index=(index+1)%period;nFilled=min(period,nFilled+1);returnCommonType!(T,float)(sum)/nFilled;}}voidmain(){SMA!(int,3)s3;SMA!(double,5)s5;foreach(immutablee;[1,2,3,4,5,5,4,3,2,1])writefln("Added %d, sma(3) = %f, sma(5) = %f",e,s3(e),s5(e));}

To avoid the floating point approximations keep piling up and growing, the code could perform a periodic sum on the whole circular queue array.

Delphi

Translation of:Pascal

Small variation of#Pascal.

programSimple_moving_average;{$APPTYPE CONSOLE}typeTMovingAverage=recordprivatebuffer:TArray<Double>;head:Integer;Capacity:Integer;Count:Integer;sum,fValue:Double;publicconstructorCreate(aCapacity:Integer);functionAdd(Value:Double):Double;procedureReset;propertyValue:DoublereadfValue;end;{ TMovingAverage }functionTMovingAverage.Add(Value:Double):Double;beginhead:=(head+1)modCapacity;sum:=sum+Value-buffer[head];buffer[head]:=Value;ifcount<capacitythenbegininc(Count);fValue:=sum/count;exit(fValue);end;fValue:=sum/Capacity;Result:=fValue;end;constructorTMovingAverage.Create(aCapacity:Integer);beginCapacity:=aCapacity;SetLength(buffer,aCapacity);Reset;end;procedureTMovingAverage.Reset;vari:integer;beginhead:=-1;Count:=0;sum:=0;fValue:=0;fori:=0toHigh(buffer)dobuffer[i]:=0;end;varavg3,avg5:TMovingAverage;i:Integer;beginavg3:=TMovingAverage.Create(3);avg5:=TMovingAverage.Create(5);fori:=1to5dobeginwrite('Inserting ',i,' into avg3 ',avg3.Add(i):0:4);writeln(' Inserting ',i,' into avg5 ',avg5.Add(i):0:4);end;fori:=5downto1dobeginwrite('Inserting ',i,' into avg3 ',avg3.Add(i):0:4);writeln(' Inserting ',i,' into avg5 ',avg5.Add(i):0:4);end;avg3.Reset;fori:=1to100000000doavg3.Add(i);writeln('100''000''000 insertions ',avg3.Value:0:4);Readln;end.
Output:
Inserting 1 into avg3 1.0000 Inserting 1 into avg5 1.0000Inserting 2 into avg3 1.5000 Inserting 2 into avg5 1.5000Inserting 3 into avg3 2.0000 Inserting 3 into avg5 2.0000Inserting 4 into avg3 3.0000 Inserting 4 into avg5 2.5000Inserting 5 into avg3 4.0000 Inserting 5 into avg5 3.0000Inserting 5 into avg3 4.6667 Inserting 5 into avg5 3.8000Inserting 4 into avg3 4.6667 Inserting 4 into avg5 4.2000Inserting 3 into avg3 4.0000 Inserting 3 into avg5 4.2000Inserting 2 into avg3 3.0000 Inserting 2 into avg5 3.8000Inserting 1 into avg3 2.0000 Inserting 1 into avg5 3.0000100'000'000 insertions 99999999.0000

Dyalect

Translation of:C#
func avg(xs) {    var acc = 0.0    var c = 0    for x in xs {        c += 1        acc += x    }    acc / c} func sma(p) {    var s = []    x => {        if s.Length() >= p {            s.RemoveAt(0)        }        s.Insert(s.Length(), x)        avg(s)    };} var nums = Iterator.Concat(1.0..5.0, 5.0^-1.0..1.0)var sma3 = sma(3)var sma5 = sma(5) for n in nums {    print("\(n)\t(sma3) \(sma3(n))\t(sma5) \(sma5(n))")}

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 ofStandard Deviation#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]}
? 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()> }Period 3:11.021.532.043.054.054.66666666666666744.66666666666666734.023.012.0Period 5:11.021.532.042.553.053.844.234.223.813.0

EasyLang

prefix sma_global p[] ind[] sum[] smpl[][] .func new p .   p[] &= p   ind[] &= 0   sum[] &= 0   smpl[][] &= [ ]   return len p[].func get id x .   ind[id] = (ind[id] + 1) mod1 p[id]   ind = ind[id]   if len smpl[id][] < ind      len smpl[id][] ind   else      sum[id] -= smpl[id][ind]   .   sum[id] += x   smpl[id][ind] = x   return sum[id] / len smpl[id][].prefix#sma5 = sma_new 5sma3 = sma_new 3numfmt 4 2for v in [ 1 2 3 4 5 5 4 3 2 1 ]   print sma_get sma3 v & "  " & sma_get sma5 v.
Output:
   1     11.50  1.50   2     2   3  2.50   4     34.67  3.804.67  4.20   4  4.20   3  3.80   2     3

EchoLisp

(lib'tree);; queues operations(define(make-smap)(defineQ(queue(gensym)))(lambda(item)(q-pushQitem)(when(>(queue-lengthQ)p)(q-popQ))(//(for/sum((x(queue->listQ)))x)(queue-lengthQ))))
Output:
(define serie '(1 2 3 4 5 5 4 3 2 1))(define sma-3 (make-sma 3))(define sma-5 (make-sma 5))(for ((x serie)) (printf "%3d %10d %10d" x (sma-3 x) (sma-5 x)))  1          1          1  2        1.5        1.5  3          2          2  4          3        2.5  5          4          3  5     4.6667        3.8  4     4.6667        4.2  3          4        4.2  2          3        3.8  1          2          3

Elena

ELENA 6.x :

import system'routines;import system'collections;import extensions;class SMA{    object thePeriod;    object theList;        constructor new(period)    {        thePeriod := period;        theList :=new List();    }        append(n)    {        theList.append(n);        var count := theList.Length;        count =>            0 : { ^0.0r }            ! : {                if (count > thePeriod)                {                    theList.removeAt(0);                                        count := thePeriod                };                        var sum := theList.summarize(Real.new());                                ^ sum / count            }    }}public Program(){    var SMA3 := SMA.new(3);    var SMA5 := SMA.new(5);    for (int i := 1; i <= 5; i += 1) {        Console.printPaddingRight(30, "sma3 + ", i, " = ", SMA3.append(i));        Console.printLine("sma5 + ", i, " = ", SMA5.append(i))    };    for (int i := 5; i >= 1; i -= 1) {        Console.printPaddingRight(30, "sma3 + ", i, " = ", SMA3.append(i));        Console.printLine("sma5 + ", i, " = ", SMA5.append(i))    };        Console.readChar()}
Output:
sma3 + 1 = 1.0                sma5 + 1 = 1.0sma3 + 2 = 1.5                sma5 + 2 = 1.5sma3 + 3 = 2.0                sma5 + 3 = 2.0sma3 + 4 = 3.0                sma5 + 4 = 2.5sma3 + 5 = 4.0                sma5 + 5 = 3.0sma3 + 5 = 4.666666666667     sma5 + 5 = 3.8sma3 + 4 = 4.666666666667     sma5 + 4 = 4.2sma3 + 3 = 4.0                sma5 + 3 = 4.2sma3 + 2 = 3.0                sma5 + 2 = 3.8sma3 + 1 = 2.0                sma5 + 1 = 3.0

Elixir

The elixir program below generates an anonymous function with an embedded period `p`, which is used as the period of the simple moving average. The `run` function reads numeric input and passes it to the newly created anonymous function, and then "inspects" the result to STDOUT.

$catsimple-moving-avg.exs#!/usr/bin/env elixirdefmoduleMathdodefaverage([]),do:nildefaverage(enum)doEnum.sum(enum)/length(enum)endenddefmoduleSMAdodefsma(l,p\\10)doIO.puts("\nSimple moving average(period=#{p}):")Enum.chunk(l,p,1)|>Enum.map(&(%{"input":&1,"avg":Float.round(Math.average(&1),3)}))enddefmacrogen_func(p)doquotedofnl->SMA.sma(l,unquote(p))endendenddefread_numeric_inputdoIO.stream(:stdio,:line)|>Enum.map(&(String.split(&1,~r{\s+})))|>List.flatten()|>Enum.reject(&(is_nil(&1)||String.length(&1)==0))|>Enum.map(&(Integer.parse(&1)|>elem(0)))enddefrundosma_func_10=gen_func(10)sma_func_15=gen_func(15)numbers=read_numeric_inputsma_func_10.(numbers)|>IO.inspectsma_func_15.(numbers)|>IO.inspectendendSMA.run
#!/bin/bashelixir./simple-moving-avg.exs<<EOF1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 12 4 6 8 10 12 14 12 10 8 6 4 2EOF

The output is shown below, with the average, followed by the grouped input, forming the basis of each moving average.

$ ./simple-moving-avg.shSimple moving average(period=10):[%{avg: 5.3, input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 8]}, %{avg: 5.9, input: [2, 3, 4, 5, 6, 7, 8, 9, 8, 7]}, %{avg: 6.3, input: [3, 4, 5, 6, 7, 8, 9, 8, 7, 6]}, %{avg: 6.5, input: [4, 5, 6, 7, 8, 9, 8, 7, 6, 5]}, %{avg: 6.5, input: [5, 6, 7, 8, 9, 8, 7, 6, 5, 4]}, %{avg: 6.3, input: [6, 7, 8, 9, 8, 7, 6, 5, 4, 3]}, %{avg: 5.9, input: [7, 8, 9, 8, 7, 6, 5, 4, 3, 2]}, %{avg: 5.3, input: [8, 9, 8, 7, 6, 5, 4, 3, 2, 1]}, %{avg: 4.7, input: [9, 8, 7, 6, 5, 4, 3, 2, 1, 2]}, %{avg: 4.2, input: [8, 7, 6, 5, 4, 3, 2, 1, 2, 4]}, %{avg: 4.0, input: [7, 6, 5, 4, 3, 2, 1, 2, 4, 6]}, %{avg: 4.1, input: [6, 5, 4, 3, 2, 1, 2, 4, 6, 8]}, %{avg: 4.5, input: [5, 4, 3, 2, 1, 2, 4, 6, 8, 10]}, %{avg: 5.2, input: [4, 3, 2, 1, 2, 4, 6, 8, 10, 12]}, %{avg: 6.2, input: [3, 2, 1, 2, 4, 6, 8, 10, 12, 14]}, %{avg: 7.1, input: [2, 1, 2, 4, 6, 8, 10, 12, 14, 12]}, %{avg: 7.9, input: [1, 2, 4, 6, 8, 10, 12, 14, 12, 10]}, %{avg: 8.6, input: [2, 4, 6, 8, 10, 12, 14, 12, 10, 8]}, %{avg: 9.0, input: [4, 6, 8, 10, 12, 14, 12, 10, 8, 6]}, %{avg: 9.0, input: [6, 8, 10, 12, 14, 12, 10, 8, 6, 4]}, %{avg: 8.6, input: [8, 10, 12, 14, 12, 10, 8, 6, 4, 2]}]Simple moving average(period=15):[%{avg: 5.2, input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3]}, %{avg: 5.267, input: [2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2]}, %{avg: 5.2, input: [3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1]}, %{avg: 5.133, input: [4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2]}, %{avg: 5.133, input: [5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 4]}, %{avg: 5.2, input: [6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 4, 6]}, %{avg: 5.333, input: [7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 4, 6, 8]}, %{avg: 5.533, input: [8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 4, 6, 8, 10]}, %{avg: 5.8, input: [9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 4, 6, 8, 10, 12]}, %{avg: 6.133, input: [8, 7, 6, 5, 4, 3, 2, 1, 2, 4, 6, 8, 10, 12, 14]}, %{avg: 6.4, input: [7, 6, 5, 4, 3, 2, 1, 2, 4, 6, 8, 10, 12, 14, 12]}, %{avg: 6.6, input: [6, 5, 4, 3, 2, 1, 2, 4, 6, 8, 10, 12, 14, 12, 10]}, %{avg: 6.733, input: [5, 4, 3, 2, 1, 2, 4, 6, 8, 10, 12, 14, 12, 10, 8]}, %{avg: 6.8, input: [4, 3, 2, 1, 2, 4, 6, 8, 10, 12, 14, 12, 10, 8, 6]}, %{avg: 6.8, input: [3, 2, 1, 2, 4, 6, 8, 10, 12, 14, 12, 10, 8, 6, 4]}, %{avg: 6.733, input: [2, 1, 2, 4, 6, 8, 10, 12, 14, 12, 10, 8, 6, 4, 2]}]

Erlang

main()->SMA3=sma(3),SMA5=sma(5),Ns=[1,2,3,4,5,5,4,3,2,1],lists:foreach(fun(N)->io:format("Added~b, sma(3) ->~f, sma(5) ->~f~n",[N,next(SMA3,N),next(SMA5,N)])end,Ns),stop(SMA3),stop(SMA5).sma(W)->{sma,spawn(?MODULE,loop,[W,[]])}.loop(Window,Numbers)->receive{_Pid,stop}->ok;{Pid,N}whenis_number(N)->caselength(Numbers)<Windowoftrue->Next=Numbers++[N];false->Next=tl(Numbers)++[N]end,Pid!{average,lists:sum(Next)/length(Next)},loop(Window,Next);_->okend.stop({sma,Pid})->Pid!{self(),stop},ok.next({sma,Pid},N)->Pid!{self(),N},receive{average,Ave}->Aveend.
Output:
9>sma:main().Added1,sma(3)->1.000000,sma(5)->1.000000Added2,sma(3)->1.500000,sma(5)->1.500000Added3,sma(3)->2.000000,sma(5)->2.000000Added4,sma(3)->3.000000,sma(5)->2.500000Added5,sma(3)->4.000000,sma(5)->3.000000Added5,sma(3)->4.666667,sma(5)->3.800000Added4,sma(3)->4.666667,sma(5)->4.200000Added3,sma(3)->4.000000,sma(5)->4.200000Added2,sma(3)->3.000000,sma(5)->3.800000Added1,sma(3)->2.000000,sma(5)->3.000000ok

Erlang has closures, but immutable variables. A solution then is to use processes and a simple message passing based API.

Euler Math Toolbox

Matrix languages have routines to compute the gliding avarages for a given sequence of items.

>n=1000; m=100; x=random(1,n);>x10=fold(x,ones(1,m)/m);>x10=fftfold(x,ones(1,m)/m)[m:n]; // more efficient

It is less efficient to loop as in the following commands.

>function store (x:number, v:vector, n:index) ...$if cols(v)<n then return v|x;$else$  v=rotleft(v); v[-1]=x;$  return v;$endif;$endfunction>v=zeros(1,0); for k=1:20; v=store(k,v,10); mean(v), end; 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6.5 7.5 8.5 9.5 10.5 11.5 12.5 13.5 14.5 15.5>v [ 11  12  13  14  15  16  17  18  19  20 ]

F#

letsmaperiodf(list:floatlist)=letsma_auxqueuev=letq=Seq.truncateperiod(v::queue)Seq.averageq,Seq.toListqList.fold(funsv->letavg,state=sma_auxsvfavgstate)[]listprintf"sma3: "[1.;2.;3.;4.;5.;5.;4.;3.;2.;1.]|>sma3(printf"%.2f ")printf"\nsma5: "[1.;2.;3.;4.;5.;5.;4.;3.;2.;1.]|>sma5(printf"%.2f ")printfn""
Output:
sma3: 1.00 1.50 2.00 3.00 4.00 4.67 4.67 4.00 3.00 2.00sma5: 1.00 1.50 2.00 2.50 3.00 3.80 4.20 4.20 3.80 3.00

Factor

TheI word creates a quotation (anonymous function) that closes over a sequence and a period. This quotation handles adding/removing numbers to the simple moving average (SMA). We can then add a number to the SMA usingsma-add and get the SMA's sequence and mean withsma-query. Quotations adhere to thesequence protocol so we can obtain the sequence of numbers simply by callingfirst on the SMA quotation.

USING:kernelinterpolateiolocalsmath.statisticsprettyprintrandomsequences;IN:rosetta-code.simple-moving-avg::I(P--quot)V{}clone:>v![vswapsuffix!Pshorttail*v!];:sma-add(quotn--quot')swaptuckcall(xx--x);:sma-query(quot--avgv)firstconcatdupmeanswap;:simple-moving-average-demo(--)5I10<iota>[oversma-queryunparse[IAfter${2}numbersSequenceis${0}Meanis${1}I]nl100randomsma-add]eachdrop;MAIN:simple-moving-average-demo
Output:
After 0 numbers Sequence is V{ } Mean is 0After 1 numbers Sequence is V{ 41 } Mean is 41After 2 numbers Sequence is V{ 41 31 } Mean is 36After 3 numbers Sequence is V{ 41 31 2 } Mean is 24+2/3After 4 numbers Sequence is V{ 41 31 2 24 } Mean is 24+1/2After 5 numbers Sequence is V{ 41 31 2 24 70 } Mean is 33+3/5After 6 numbers Sequence is V{ 31 2 24 70 80 } Mean is 41+2/5After 7 numbers Sequence is V{ 2 24 70 80 96 } Mean is 54+2/5After 8 numbers Sequence is V{ 24 70 80 96 84 } Mean is 70+4/5After 9 numbers Sequence is V{ 70 80 96 84 7 } Mean is 67+2/5

Fantom

class MovingAverage {  Int period  Int[] stream   new make (Int period)  {    this.period = period    stream = [,]  }  // add number to end of stream and remove numbers from start if   // stream is larger than period  public Void addNumber (Int number)  {    stream.add (number)    while (stream.size > period)    {      stream.removeAt (0)    }  }  // compute average of numbers in stream  public Float average ()  {    if (stream.isEmpty)      return 0.0f    else      1.0f * (Int)(stream.reduce(0, |a,b| { (Int) a + b })) / stream.size  }}class Main{  public static Void main ()  { // test by adding random numbers and printing average after each number    av := MovingAverage (5)    10.times |i|    {      echo ("After $i numbers list is ${av.stream} average is ${av.average}")      av.addNumber (Int.random(0..100))    }  }}
Output:

for a period of 5

After 0 numbers list is [,] average is 0.0After 1 numbers list is [64] average is 64.0After 2 numbers list is [64, 50] average is 57.0After 3 numbers list is [64, 50, 26] average is 46.666666666666664After 4 numbers list is [64, 50, 26, 77] average is 54.25After 5 numbers list is [64, 50, 26, 77, 82] average is 59.8After 6 numbers list is [50, 26, 77, 82, 95] average is 66.0After 7 numbers list is [26, 77, 82, 95, 11] average is 58.2After 8 numbers list is [77, 82, 95, 11, 23] average is 57.6After 9 numbers list is [82, 95, 11, 23, 50] average is 52.2

Forth

:f+!( f addr -- )dupf@f+f!;:,f0s( n -- )falign0do0ef,loop;:period@;:usedcell+;:head2cells+;:sum3cells+faligned;:ring( addr -- faddr )dupsumfloat+swaphead@floats+;:update( fvalue addr -- addr )dupringf@fnegatedupsumf+!fdupdupringf!dupsumf+!duphead@1+overperiodmodoverhead!;:moving-averagecreate( period -- )dup,0,0,1+,f0sdoes>( fvalue -- avg )updatedupused@overperiod<if1overused+!thendupsumf@used@0d>ff/;3moving-averagesma1esmaf.\ 1.2esmaf.\ 1.53esmaf.\ 2.4esmaf.\ 3.

Fortran

Works with:Fortran version 90 and later
programMovavgimplicit noneinteger::iwrite(*,"(a)")"SIMPLE MOVING AVERAGE: PERIOD = 3"doi=1,5write(*,"(a, i2, a, f8.6)")"Next number:",i,"   sma = ",sma(real(i))end do  doi=5,1,-1write(*,"(a, i2, a, f8.6)")"Next number:",i,"   sma = ",sma(real(i))end docontainsfunctionsma(n)real::smareal,intent(in)::nreal,save::a(3)=0integer,save::count=0if(count<3)thencount=count+1a(count)=nelsea=eoshift(a,1,n)end ifsma=sum(a(1:count))/real(count)end functionend programMovavg

FreeBASIC

' FB 1.05.0 Win64TypeFuncTypeAsFunction(AsDouble)AsDouble' These 'shared' variables are available to all functions defined belowDimSharedpAsUIntegerDimSharedlist()AsDoubleFunctionsma(nAsDouble)AsDoubleRedimPreservelist(0ToUBound(list)+1)list(UBound(list))=nDimstartAsInteger=0DimlengthAsInteger=UBound(list)+1Iflength>pThenstart=UBound(list)-p+1length=pEndIfDimsumAsDouble=0.0ForiAsInteger=startToUBound(list)sum+=list(i)NextReturnsum/lengthEndFunctionFunctioninitSma(periodAsUinteger)AsFuncTypep=periodEraselist'' ensure the array is empty on each initializationReturn@smaEndFunctionDimAsFuncTypema=initSma(3)Print"Period = ";pPrintForiAsInteger=0To9Print"Add";i;" => moving average =";ma(i)NextPrintma=initSma(5)Print"Period = ";pPrintForiAsInteger=9To0Step-1Print"Add";i;" => moving average =";ma(i)NextPrintPrint"Press any key to quit"Sleep
Output:
Period = 3Add 0 => moving average = 0Add 1 => moving average = 0.5Add 2 => moving average = 1Add 3 => moving average = 2Add 4 => moving average = 3Add 5 => moving average = 4Add 6 => moving average = 5Add 7 => moving average = 6Add 8 => moving average = 7Add 9 => moving average = 8Period = 5Add 9 => moving average = 9Add 8 => moving average = 8.5Add 7 => moving average = 8Add 6 => moving average = 7.5Add 5 => moving average = 7Add 4 => moving average = 6Add 3 => moving average = 5Add 2 => moving average = 4Add 1 => moving average = 3Add 0 => moving average = 2

GAP

MovingAverage:=function(n)localsma,buffer,pos,sum,len;buffer:=List([1..n],i->0);pos:=0;len:=0;sum:=0;sma:=function(x)pos:=RemInt(pos,n)+1;sum:=sum+x-buffer[pos];buffer[pos]:=x;len:=Minimum(len+1,n);returnsum/len;end;returnsma;end;f:=MovingAverage(3);f(1);#  1f(2);#  3/2f(3);#  2f(4);#  3f(5);#  4f(5);#  14/3f(4);#  14/3f(3);#  4f(2);#  3f(1);#  2

Go

packagemainimport"fmt"funcsma(periodint)func(float64)float64{variintvarsumfloat64varstorage=make([]float64,0,period)returnfunc(inputfloat64)(avrgfloat64){iflen(storage)<period{sum+=inputstorage=append(storage,input)}sum+=input-storage[i]storage[i],i=input,(i+1)%periodavrg=sum/float64(len(storage))return}}funcmain(){sma3:=sma(3)sma5:=sma(5)fmt.Println("x       sma3   sma5")for_,x:=range[]float64{1,2,3,4,5,5,4,3,2,1}{fmt.Printf("%5.3f  %5.3f  %5.3f\n",x,sma3(x),sma5(x))}}
Output:
x       sma3   sma51.000  1.000  1.0002.000  1.500  1.5003.000  2.000  2.0004.000  3.000  2.5005.000  4.000  3.0005.000  4.667  3.8004.000  4.667  4.2003.000  4.000  4.2002.000  3.000  3.8001.000  2.000  3.000

Groovy

Translation of:Ruby
defsimple_moving_average={size->defnums=[]doubletotal=0.0return{newElement->nums+=newElementoldestElement=nums.size()>size?nums.remove(0):0total+=newElement-oldestElementtotal/nums.size()}}ma5=simple_moving_average(5)(1..5).each{printf("%1.1f ",ma5(it))}(5..1).each{printf("%1.1f ",ma5(it))}
Output:
1.0 1.5 2.0 2.5 3.0 3.8 4.2 4.2 3.8 3.0

Haskell

Conform version to the requirement, function SMA called multiple times with just a number:

Works with:GHC version 6.10.4
{-# LANGUAGE BangPatterns #-}importControl.MonadimportData.ListimportData.IORefdataPairab=Pair!a!bmean::Fractionala=>[a]->amean=divl.foldl'(\(Pairsl)x->Pair(s+x)(l+1))(Pair0.00)wheredivl(_,0)=0.0divl(s,l)=s/fromIntegrallseries=[1,2,3,4,5,5,4,3,2,1]mkSMA::Int->IO(Double->IODouble)mkSMAperiod=avgr<$>newIORef[]whereavgrnsrefx=readIORefnsref>>=(\ns->letxs=takeperiod(x:ns)inwriteIORefnsrefxs$>meanxs)main=mkSMA3>>=(\sma3->mkSMA5>>=(\sma5->mapM_(str<$>puren<*>sma3<*>sma5)series))wherestrnmm3mm5=concat["Next number = ",shown,", SMA_3 = ",showmm3,", SMA_5 = ",showmm5]
Output:
Next number = 1.0, SMA_3 = 1.0, SMA_5 = 1.0Next number = 2.0, SMA_3 = 1.5, SMA_5 = 1.5Next number = 3.0, SMA_3 = 2.0, SMA_5 = 2.0Next number = 4.0, SMA_3 = 3.0, SMA_5 = 2.5Next number = 5.0, SMA_3 = 4.0, SMA_5 = 3.0Next number = 5.0, SMA_3 = 4.666666666666667, SMA_5 = 3.8Next number = 4.0, SMA_3 = 4.666666666666667, SMA_5 = 4.2Next number = 3.0, SMA_3 = 4.0, SMA_5 = 4.2Next number = 2.0, SMA_3 = 3.0, SMA_5 = 3.8Next number = 1.0, SMA_3 = 2.0, SMA_5 = 3.0


Works with:GHC version 6.10.4
importData.ListimportControl.ArrowimportControl.MonadsMAp=map(head***head).tail.scanl(\(y,_)->(id&&&return.av).(:iflengthy==ptheninityelsey))([],[])whereav=liftM2(/)sum(fromIntegral.length)printSMAnp=mapM_(\(n,a)->putStrLn$"Next number: "++shown++"  Average: "++showa).taken.sMAp$[1..5]++[5,4..1]++[3..]

Stateful function using the state monad to keep track of state

Works with:GHC version 7.8.3
importControl.MonadimportControl.Monad.Stateperiod::Intperiod=3typeSMAState=[Float]computeSMA::Float->StateSMAStateFloatcomputeSMAx=dopreviousValues<-getletvalues=previousValues++[x]letnewAverage=iflengthvalues<=periodthen(sumvalues)/(fromIntegral$lengthremainingValues::Float)else(sumremainingValues)/(fromIntegral$lengthremainingValues::Float)whereremainingValues=dropIfperiodvaluesput$dropIfperiodvaluesreturnnewAveragedropIf::Int->[a]->[a]dropIfxxs=drop((lengthxs)-x)xsdemostrateSMA::StateSMAState[Float]demostrateSMA=mapMcomputeSMA[1,2,3,4,5,5,4,3,2,1]main::IO()main=print$evalStatedemostrateSMA[]
Output:
[1.0,1.5,2.0,3.0,4.0,4.6666665,4.6666665,4.0,3.0,2.0]

HicEst

REAL :: n=10, nums(n)nums = (1,2,3,4,5, 5,4,3,2,1)DO i = 1, n   WRITE() "num=", i, "SMA3=", SMA(3,nums(i)), "SMA5=",SMA(5,nums(i))ENDDOEND ! of "main"FUNCTION SMA(period, num) ! maxID independent streams REAL :: maxID=10, now(maxID), Periods(maxID), Offsets(maxID), Pool(1000)   ID = INDEX(Periods, period)   IF( ID == 0) THEN ! initialization     IDs = IDs + 1     ID = IDs     Offsets(ID) = SUM(Periods) + 1     Periods(ID) = period   ENDIF   now(ID) = now(ID) + 1   ALIAS(Pool,Offsets(ID),   Past,Periods(ID)) ! renames relevant part of data pool   Past = Past($+1) ! shift left   Past(Periods(ID)) = num   SMA = SUM(Past) / MIN( now(ID), Periods(ID) ) END
num=1 SMA3=1 SMA5=1num=2 SMA3=1.5 SMA5=1.5num=3 SMA3=2 SMA5=2num=4 SMA3=3 SMA5=2.5num=5 SMA3=4 SMA5=3num=6 SMA3=4.666666667 SMA5=3.8num=7 SMA3=4.666666667 SMA5=4.2num=8 SMA3=4 SMA5=4.2num=9 SMA3=3 SMA5=3.8num=10 SMA3=2 SMA5=3

Icon andUnicon

proceduremain(A)sma:=buildSMA(3)# Use better name than "I".everywrite(sma(!A))endprocedurebuildSMA(P)localstreamc:=create{stream:=[]whilen:=(avg@&source)[1]do{put(stream,n)if*stream>Pthenpop(stream)every(avg:=0.0)+:=!streamavg:=avg/*stream}}return(@c,c)end

Note: This program uses Unicon specific co-expression calling syntax. It can be easily modified to run under Icon.

and a sample run:

->ravg 3 1 4 1 5 9 2 6 3 83.02.02.6666666666666672.03.3333333333333335.05.3333333333333335.6666666666666673.6666666666666675.666666666666667->

If theUtils package is imported from theUnicon code library then a (Unicon only) solution is:

importUtilsproceduremain(A)sma1:=closure(SMA,[],3)sma2:=closure(SMA,[],4)everyeveryn:=!Adowrite(left(sma1(n),20),sma2(n))endprocedureSMA(stream,P,n)put(stream,n)if*stream>Pthenpop(stream)every(avg:=0.0)+:=!streamreturnavg/*streamend

with the sample run:

->ravg 3 1 4 1 5 9 2 6 3 83.0                 3.02.0                 2.02.666666666666667   2.6666666666666672.0                 2.253.333333333333333   2.755.0                 4.755.333333333333333   4.255.666666666666667   5.53.666666666666667   5.05.666666666666667   4.75->

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(+/%#)\, though it is worth noting that this approach does not provide averages for the initial cases where not all data would be available yet:

5(+/%#)\1234554321NB. not a solution for this task33.84.24.23.83

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 toimplement it. Thus thestreaming solution is more complex:

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

Example:

sma=:5lexsma&>123455432111.522.533.84.24.23.83

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

Or, a more traditional approach could be used:

avg=:+/%#SEQ=:''moveAvg=:4 :0"0SEQ=:SEQ,yavg({.~x-@<.#)SEQ)5moveAvg123455432111.522.533.84.24.23.83

Java

Works with:Java version 1.5+
importjava.util.LinkedList;importjava.util.Queue;publicclassMovingAverage{privatefinalQueue<Double>window=newLinkedList<Double>();privatefinalintperiod;privatedoublesum;publicMovingAverage(intperiod){assertperiod>0:"Period must be a positive integer";this.period=period;}publicvoidnewNum(doublenum){sum+=num;window.add(num);if(window.size()>period){sum-=window.remove();}}publicdoublegetAvg(){if(window.isEmpty())return0.0;// technically the average is undefinedreturnsum/window.size();}publicstaticvoidmain(String[]args){double[]testData={1,2,3,4,5,5,4,3,2,1};int[]windowSizes={3,5};for(intwindSize:windowSizes){MovingAveragema=newMovingAverage(windSize);for(doublex:testData){ma.newNum(x);System.out.println("Next number = "+x+", SMA = "+ma.getAvg());}System.out.println();}}}
Output:
Next number = 1.0, SMA = 1.0Next number = 2.0, SMA = 1.5Next number = 3.0, SMA = 2.0Next number = 4.0, SMA = 3.0Next number = 5.0, SMA = 4.0Next number = 5.0, SMA = 4.666666666666667Next number = 4.0, SMA = 4.666666666666667Next number = 3.0, SMA = 4.0Next number = 2.0, SMA = 3.0Next number = 1.0, SMA = 2.0Next number = 1.0, SMA = 1.0Next number = 2.0, SMA = 1.5Next number = 3.0, SMA = 2.0Next number = 4.0, SMA = 2.5Next number = 5.0, SMA = 3.0Next number = 5.0, SMA = 3.8Next number = 4.0, SMA = 4.2Next number = 3.0, SMA = 4.2Next number = 2.0, SMA = 3.8Next number = 1.0, SMA = 3.0

JavaScript

Using for loop

functionsimple_moving_averager(period){varnums=[];returnfunction(num){nums.push(num);if(nums.length>period)nums.splice(0,1);// remove the first element of the arrayvarsum=0;for(variinnums)sum+=nums[i];varn=period;if(nums.length<period)n=nums.length;return(sum/n);}}varsma3=simple_moving_averager(3);varsma5=simple_moving_averager(5);vardata=[1,2,3,4,5,5,4,3,2,1];for(variindata){varn=data[i];// using WSHWScript.Echo("Next number = "+n+", SMA_3 = "+sma3(n)+", SMA_5 = "+sma5(n));}
Output:
Next number = 1, SMA_3 = 1, SMA_5 = 1Next number = 2, SMA_3 = 1.5, SMA_5 = 1.5Next number = 3, SMA_3 = 2, SMA_5 = 2Next number = 4, SMA_3 = 3, SMA_5 = 2.5Next number = 5, SMA_3 = 4, SMA_5 = 3Next number = 5, SMA_3 = 4.666666666666667, SMA_5 = 3.8Next number = 4, SMA_3 = 4.666666666666667, SMA_5 = 4.2Next number = 3, SMA_3 = 4, SMA_5 = 4.2Next number = 2, SMA_3 = 3, SMA_5 = 3.8Next number = 1, SMA_3 = 2, SMA_5 = 3

Using reduce/filter

JS Fiddle

// single-sidedArray.prototype.simpleSMA=function(N){returnthis.map(function(el,index,_arr){return_arr.filter(function(x2,i2){returni2<=index&&i2>index-N;}).reduce(function(current,last,index,arr){return(current+last);})/index||1;});};g=[0,1,2,3,4,5,6,7,8,9,10];console.log(g.simpleSMA(3));console.log(g.simpleSMA(5));console.log(g.simpleSMA(g.length));
Output:
[1, 1, 1.5, 2, 2.25, 2.4, 2.5, 2.5714285714285716, 2.625, 2.6666666666666665, 2.7][1, 1, 1.5, 2, 2.5, 3, 3.3333333333333335, 3.5714285714285716, 3.75, 3.888888888888889, 4][1, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5]

jq

Works with jq, the C implementation of jq

Works with gojq, the Go implementation of jq

Works with jaq, the Rust implementation of jq

jq functions are stateless, so in this entry, sma($x) is definedas a parameterized jq filter that takes as input the relevant state as a JSON object.This should initially include a key named "period" specifying the period,which may be infinite, i.e. the jq value `infinite` corresponding to positive infinity.

For example the initial call to sma/1 might look like:

{period: infinite} | sma(100)

Two examples are given, one with a finite and the other with an infinite period.Both compute the average of the 11 numbers 0, 1, ... 10, by calling sma(0) and then sma(1), and so on.

# The input should be a JSON object with a key named "period".# The output is a JSON object with a key named "average" giving the SMA.def sma($x):  def average:    .n as $n    | if $n == null or $n == 0 then . + {n: 1, average: $x}      else .average |= (. * $n + $x) / ($n + 1)      | .n += 1      end;      if . == null or (.period and .period < 1)  then "The initial call to sma/1 must specify the period properly" | error  elif .n and .n < 0 then "Invalid value of .n" | error  elif (.period | isinfinite) then average  elif .n == null or .n == 0 then . + {n: 1, average: $x, array: [$x]}  else .n as $n  | if $n < .period    then .array += [$x]    | .n += 1    else .array |= .[1:] + [$x]    end  | .average = (.array | (add/length))  end;# Call sma($x) for the 11 numbers 0, 1, ... 10.def example($period): reduce range(0;11) as $x({period: $period}; sma($x)) | .average ;example(11), example(infinite)
Output:
55

Julia

usingStatistics

The function wants specified the type of the data in the buffer and, if you want, the limit of the buffer.

functionmovingaverage(::Type{T}=Float64;lim::Integer=-1)whereT<:Realbuffer=Vector{T}(0)iflim==-1# unlimited bufferreturn(y::T)->beginpush!(buffer,y)returnmean(buffer)endelse# limited size bufferreturn(y)->beginpush!(buffer,y)iflength(buffer)>limshift!(buffer)endreturnmean(buffer)endendendtest=movingaverage()@showtest(1.0)# mean([1])@showtest(2.0)# mean([1, 2])@showtest(3.0)# mean([1, 2, 3])
Output:
test(1.0) = 1.0test(2.0) = 1.5test(3.0) = 2.0

K

Non-stateful:

v:v,|v:1+!5v1234554321avg:{(+/x)%#x}sma:{avg'x@(,\!y),(1+!y)+\:!y}sma[v;5]11.522.533.84.24.23.83

Stateful:

sma:{n::x#_n;{n::1_n,x;{avgx@&~_n~'x}n}}sma[5]'v11.522.533.84.24.23.83

Kotlin

// version 1.0.6funinitMovingAverage(p:Int):(Double)->Double{if(p<1)throwIllegalArgumentException("Period must be a positive integer")vallist=mutableListOf<Double>()return{list.add(it)if(list.size>p)list.removeAt(0)list.average()}}funmain(args:Array<String>){valsma4=initMovingAverage(4)valsma5=initMovingAverage(5)valnumbers=listOf(1.0,2.0,3.0,4.0,5.0,5.0,4.0,3.0,2.0,1.0)println("num\tsma4\tsma5\n")for(numberinnumbers)println("${number}\t${sma4(number)}\t${sma5(number)}")}
Output:
num     sma4    sma51.0     1.0     1.02.0     1.5     1.53.0     2.0     2.04.0     2.5     2.55.0     3.5     3.05.0     4.25    3.84.0     4.5     4.23.0     4.25    4.22.0     3.5     3.81.0     2.5     3.0

Lasso

This example isincorrect. Please fix the code and remove this message.

Details: routine is called with a list of multiple numbers rather than being called with individual numbers in succession.

definesimple_moving_average(a::array,s::integer)::decimal=>{#a->size==0?return0.00#s==0?return0.00#a->size==1?returndecimal(#a->first)#s==1?returndecimal(#a->last)local(na=array)if(#a->size<=#s)=>{#na=#aelselocal(ar=#a->ascopy)#ar->reverseloop(#s)=>{#na->insert(#ar->get(loop_count))}}#s>#na->size?#s=#na->sizereturn(withein#nasum#e)/decimal(#s)}// tests:'SMA 3 on array(1,2,3,4,5,5,4,3,2,1): 'simple_moving_average(array(1,2,3,4,5,5,4,3,2,1),3)'\rSMA 5 on array(1,2,3,4,5,5,4,3,2,1): 'simple_moving_average(array(1,2,3,4,5,5,4,3,2,1),5)'\r\rFurther example:\r'local(mynumbers=array,sma_num=5)loop(10)=>{^#mynumbers->insert(integer_random(1,100))#mynumbers->size+' numbers: '+#mynumbers' SMA3 is: '+simple_moving_average(#mynumbers,3)', SMA5 is: '+simple_moving_average(#mynumbers,5)'\r'^}
Output:
SMA 3 on array(1,2,3,4,5,5,4,3,2,1): 2.000000SMA 5 on array(1,2,3,4,5,5,4,3,2,1): 3.000000Further example: 1 numbers: array(91) SMA3 is: 91.000000, SMA5 is: 91.0000002 numbers: array(91, 30) SMA3 is: 60.500000, SMA5 is: 60.5000003 numbers: array(91, 30, 99) SMA3 is: 73.333333, SMA5 is: 73.3333334 numbers: array(91, 30, 99, 73) SMA3 is: 67.333333, SMA5 is: 73.2500005 numbers: array(91, 30, 99, 73, 22) SMA3 is: 64.666667, SMA5 is: 63.0000006 numbers: array(91, 30, 99, 73, 22, 35) SMA3 is: 43.333333, SMA5 is: 51.8000007 numbers: array(91, 30, 99, 73, 22, 35, 93) SMA3 is: 50.000000, SMA5 is: 64.4000008 numbers: array(91, 30, 99, 73, 22, 35, 93, 24) SMA3 is: 50.666667, SMA5 is: 49.4000009 numbers: array(91, 30, 99, 73, 22, 35, 93, 24, 8) SMA3 is: 41.666667, SMA5 is: 36.40000010 numbers: array(91, 30, 99, 73, 22, 35, 93, 24, 8, 80) SMA3 is: 37.333333, SMA5 is: 48.000000

Liberty BASIC

The interesting thing here is how to implement an equivalent of a stateful function.For sample output seehttp://libertybasic.conforums.com/index.cgi?board=open&action=display&num=1322956720

    dim v$( 100)                                                            '   Each array term stores a particular SMA of period p in p*10 bytes    nomainwin    WindowWidth  =1080    WindowHeight = 780    graphicbox #w.gb1,   20,   20, 1000,  700    open "Running averages to smooth data" for window as #w    #w "trapclose quit"    #w.gb1 "down"    old.x         =  0    old.y.orig    =500  '   black    old.y.3.SMA   =350  '     red    old.y.20.SMA  =300  '   green    for i =0 to 999 step 1        scan        v       =1.1 +sin( i /1000 *2 *3.14159265) + 0.2 *rnd( 1)               '   sin wave with added random noise        x       =i /6.28318 *1000        y.orig  =500 -v /2.5 *500        #w.gb1 "color black ; down ; line "; i-1; " "; old.y.orig;  " "; i; " "; y.orig;         " ; up"        y.3.SMA =500 -SMA( 1, v,  3) /2.5 *500                                  '   SMA given ID of 1 is to do 3-term  running average        #w.gb1 "color red   ; down ; line "; i-1; " "; old.y.3.SMA +50;  " "; i; " "; y.3.SMA  +50;  " ; up"        y.20.SMA =500 -SMA( 2, v, 20) /2.5 *500                                 '   SMA given ID of 2 is to do 20-term running average        #w.gb1 "color green ; down ; line "; i-1; " "; old.y.20.SMA +100; " "; i; " "; y.20.SMA +100; " ; up"        'print "Supplied with "; v; ", so SMAs are now "; using( "###.###", SMA( 1, v, 3)); " over 3 terms or "; using( "###.###", SMA( 2, v, 5)) ; " over 5 terms."  '   ID, latest data, period        old.y.orig    =y.orig        old.y.3.SMA   =y.3.SMA        old.y.20.SMA  =y.20.SMA    next i    waitsub quit j$    close #w    endend subfunction SMA( ID, Number, Period)    v$( ID) =right$( "          " +str$( Number), 10) +v$( ID)              '   add new number at left, lose last number on right    v$( ID) =left$( v$( ID), Period *10)    'print "{"; v$( ID); "}",    k      =0   '   number of terms read    total  =0   '   sum of terms read    do        p$     =mid$( v$( ID), 1 +k *10, 10)        if p$ ="" then exit do        vv     =val( p$)        total  =total +vv        k      =k +1    loop until p$ =""    if k <Period then SMA =total / k else  SMA =total /Periodend function

Logo

Although Logo does not support closures, some varieties of Logo support enough metaprogramming to accomplish this task.

Works with:UCB Logo

UCB Logo has a DEFINE primitive to construct functions from structured instruction lists. In addition, UCB Logo supports a compact template syntax for quoting lists (backquote "`") and replacing components of quoted lists (comma ","). These facilities can be used together in order to create templated function-defining-functions.

to average :l  output quotient apply "sum :l count :lendto make.sma :name :period  localmake "qn word :name ".queue  make :qn []  define :name `[ [n]              ; parameter list    [if equal? count :,:qn ,:period [ignore dequeue ",:qn]]    [queue ",:qn :n]    [output average :,:qn]  ]endmake.sma "avg3 3show map "avg3 [1 2 3 4 5]     ; [1 1.5 2 3 4]show text "avg3     ; examine what substitutions took place[[n] [if equal? count :avg3.queue 3 [ignore dequeue "avg3.queue]] [queue "avg3.queue :n] [output average :avg3.queue]]; the internal queue is in the global namespace, easy to inspectshow :avg3.queue    ; [3 4 5]

If namespace pollution is a concern, UCB Logo supplies a GENSYM command to obtain unique names in order to avoid collisions.

  ...  localmake "qn word :name gensym  ...; list user-defined functions and variablesshow procedures     ; [average avg3 make.sma]show names          ; [[[] [avg3.g1]]

Lua

functionsma(period)localt={}functionsum(t)sum=0for_,vinipairs(t)dosum=sum+vendreturnsumendfunctionaverage(n)if#t==periodthentable.remove(t,1)endt[#t+1]=nreturnsum(t)/#tendreturnaverageendsma5=sma(5)sma10=sma(10)print("SMA 5")forv=1,15doprint(sma5(v))endprint("\nSMA 10")forv=1,15doprint(sma10(v))end

M2000 Interpreter

Using Lambda Function

moduleSimple_moving_average{smaMAKER=lambda(m)->{s=stack=lambdam,s(N)->{stacks{iflen(s)=mthendropdataN}=array(stack(s))#sum()/len(s)}}Print"Period = 3"ma=smaMaker(3)test(0,9)Print"Period = 5"ma=smaMaker(5)test(9,0)endsubtest(A,B)localiPrintfori=AtoBPrint"Add ";i;" => moving average ";ma(i)nextPrintendsub}Simple_moving_average

Using Class

moduleSimple_moving_average{classsmaMaker{private:s=stackmpublic:set{readthis}value(N){stack.s{iflen(.s)=.mthendropdataN}=array(stack(.s))#sum()/len(.s)}class:modulesmaMaker(.m){}}Print"Period = 3"ma=smaMaker(3)test(0,9)Print"Period = 5"ma=smaMaker(5)test(9,0)endsubtest(A,B)localiPrintfori=AtoBPrint"Add ";i;" => moving average  ";ma(i)nextPrintendsub}Simple_moving_average
Output:
Period = 3Add 0 => moving average = 0Add 1 => moving average = 0.5Add 2 => moving average = 1Add 3 => moving average = 2Add 4 => moving average = 3Add 5 => moving average = 4Add 6 => moving average = 5Add 7 => moving average = 6Add 8 => moving average = 7Add 9 => moving average = 8Period = 5Add 9 => moving average = 9Add 8 => moving average = 8.5Add 7 => moving average = 8Add 6 => moving average = 7.5Add 5 => moving average = 7Add 4 => moving average = 6Add 3 => moving average = 5Add 2 => moving average = 4Add 1 => moving average = 3Add 0 => moving average = 2

Mathematica /Wolfram Language

This version uses a list entry so it can use the built-in function.

MA[x_List,r_]:=Join[Table[Mean[x[[1;;y]]],{y,r-1}],MovingAverage[x,r]]

This version is stateful instead.

MAData={{},0};MAS[x_,t_:Null]:=With[{r=If[t===Null,MAData[[2]],t]},Mean[MAData[[1]]=If[Length[#]>(MAData[[2]]=r),#[[-r;;-1]],#]&@Append[MAData[[1]],x]]]

Tests:

MA[{1, 2, 3, 4, 5, 5, 4, 3, 2, 1}, 5]=> {1, 3/2, 2, 5/2, 3, 19/5, 21/5, 21/5, 19/5, 3}MAS[1, 5]  => 1MAS[2]     => 3/2MAS[3]     => 2MAS[4]     => 5/2MAS[5]     => 3MAS[5]     => 19/5MAS[4]     => 21/5MAS[3]     => 21/5MAS[2]     => 19/5MAS[1]     => 3

MATLAB /Octave

Matlab and Octave provide very efficient and fast functions, that can be applied to vectors (i.e. series of data samples)

[m,z]=filter(ones(1,P),P,x);

m is the moving average, z returns the state at the end of the data series, which can be used to continue the moving average.

[m,z]=filter(ones(1,P),P,x,z);

Mercury

In Mercury, an idiomatic "moving averages" function would be 'stateless' - or rather, it would haveexplicit state that its callers would have to thread through uses of it:

    % state(period, list of floats from [newest, ..., oldest]):- type state ---> state(int, list(float)).:- func init(int) = state.init(Period) = state(Period, []).:- pred sma(float::in, float::out, state::in, state::out) is det.sma(N, Average, state(P, L0), state(P, L)) :-        take_upto(P, [N|L0], L),        Average = foldl((+), L, 0.0) / float(length(L)).

Some notes about this solution: unless P = 0, length(L) can never be 0, as L always incorporates at least N (a step that is accomplished in the arguments to list.take_upto/3). If the implementation of the 'state' type is hidden, and if init/1 checks for P = 0, users of this code can never cause a division-by-zero error in sma/4. Although this solution doesn't try to be as stateful as the task description would like, explicit state is by far simpler and more natural and more straightforward than the alternative in Mercury. Finally,state variables (and higher-order functions that anticipate threaded state) remove much of the potential ugliness or error in threading the same state through many users.

MiniScript

We define an SMA class, which can be configured with the desired window size (P).

SMA={}SMA.P=5// (a default; may be overridden)SMA.buffer=nullSMA.next=function(n)ifself.buffer==nullthenself.buffer=[]self.buffer.pushnifself.buffer.len>self.Pthenself.buffer.pullreturnself.buffer.sum/self.buffer.lenendfunctionsma3=newSMAsma3.P=3sma5=newSMAforiinrange(10)num=round(rnd*100)print"num: "+num+"  sma3: "+sma3.next(num)+"  sma5: "+sma5.next(num)endfor
Output:
num: 81 sma3: 81 sma5: 81num: 82 sma3: 81.5 sma5: 81.5num: 78 sma3: 80.333333 sma5: 80.333333num: 54 sma3: 71.333333 sma5: 73.75num: 94 sma3: 75.333333 sma5: 77.8num: 8 sma3: 52 sma5: 63.2num: 40 sma3: 47.333333 sma5: 54.8num: 98 sma3: 48.666667 sma5: 58.8num: 48 sma3: 62 sma5: 57.6num: 41 sma3: 62.333333 sma5: 47num: 94 sma3: 61 sma5: 64.2

NetRexx

Translation of:Java
/* NetRexx */optionsreplaceformatcommentsjavacrossrefsymbolsnobinarynumericdigits20classRAvgSimpleMovingpublicpropertiesprivatewindow=java.util.QueueperiodsumpropertiesconstantexMsg='Period must be a positive integer'--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~methodRAvgSimpleMoving(period_)publicif\period_.datatype('w')thensignalRuntimeException(exMsg)ifperiod_<=0thensignalRuntimeException(exMsg)window=LinkedList()period=period_sum=0return--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~methodnewNum(num)publicsum=sum+numwindow.add(num)ifwindow.size()>periodthendormv=(Rexxwindow.remove())sum=sum-rmvendreturn--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~methodgetAvg()publicreturnsRexxifwindow.isEmpty()thendoavg=0endelsedoavg=sum/window.size()endreturnavg--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~methodrun_samples(args=String[])publicstatictestData=[Rexx1,2,3,4,5,5,4,3,2,1]windowSizes=[Rexx3,5]loopwindSizeoverwindowSizesma=RAvgSimpleMoving(windSize)loopxValovertestDatama.newNum(xVal)say'Next number ='xVal.right(5)', SMA ='ma.getAvg().format(10,9)endxValsayendwindSizereturn--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~methodmain(args=String[])publicstaticrun_samples(args)return
Output:
Next number =   1.0, SMA =          1.000000000Next number =   2.0, SMA =          1.500000000Next number =   3.0, SMA =          2.000000000Next number =   4.0, SMA =          3.000000000Next number =   5.0, SMA =          4.000000000Next number =   5.0, SMA =          4.666666667Next number =   4.0, SMA =          4.666666667Next number =   3.0, SMA =          4.000000000Next number =   2.0, SMA =          3.000000000Next number =   1.0, SMA =          2.000000000Next number =   1.0, SMA =          1.000000000Next number =   2.0, SMA =          1.500000000Next number =   3.0, SMA =          2.000000000Next number =   4.0, SMA =          2.500000000Next number =   5.0, SMA =          3.000000000Next number =   5.0, SMA =          3.800000000Next number =   4.0, SMA =          4.200000000Next number =   3.0, SMA =          4.200000000Next number =   2.0, SMA =          3.800000000Next number =   1.0, SMA =          3.000000000

Nim

importdequesprocsimplemovingaverage(period:int):auto=assertperiod>0varsumm,n=0.0values:Deque[float]foriin1..period:values.addLast(0)procsma(x:float):float=values.addLast(x)summ+=x-values.popFirst()n=min(n+1,float(period))result=summ/nreturnsmavarsma=simplemovingaverage(3)foriin1..5:echosma(float(i))foriincountdown(5,1):echosma(float(i))echo""varsma2=simplemovingaverage(5)foriin1..5:echosma2(float(i))foriincountdown(5,1):echosma2(float(i))
Output:
1.01.52.03.04.04.6666666666666674.6666666666666674.03.02.01.01.52.02.53.03.84.24.23.83.0

Objeck

Translation of:Java
use Collection;class MovingAverage {  @window : FloatQueue;  @period : Int;  @sum : Float;  New(period : Int) {    @window := FloatQueue->New();    @period := period;  }  method : NewNum(num : Float) ~ Nil {    @sum += num;    @window->Add(num);    if(@window->Size() > @period) {      @sum -= @window->Remove();    };  }    method : GetAvg() ~ Float {    if(@window->IsEmpty()) {      return 0; # technically the average is undefined    };      return @sum / @window->Size();  }  function : Main(args : String[]) ~ Nil {    testData := [1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 4.0, 3.0, 2.0, 1.0];    windowSizes := [3.0, 5.0];      each(i : windowSizes) {      windSize := windowSizes[i];      ma := MovingAverage->New(windSize);      each(j : testData) {        x := testData[j];        ma->NewNum(x);        avg := ma->GetAvg();        "Next number = {$x}, SMA = {$avg}"->PrintLine();      };      IO.Console->PrintLine();    };  }}
Output:
Next number = 1.0, SMA = 1.0Next number = 2.0, SMA = 1.500Next number = 3.0, SMA = 2.0Next number = 4.0, SMA = 3.0Next number = 5.0, SMA = 4.0Next number = 5.0, SMA = 4.667Next number = 4.0, SMA = 4.667Next number = 3.0, SMA = 4.0Next number = 2.0, SMA = 3.0Next number = 1.0, SMA = 2.0Next number = 1.0, SMA = 1.0Next number = 2.0, SMA = 1.500Next number = 3.0, SMA = 2.0Next number = 4.0, SMA = 2.500Next number = 5.0, SMA = 3.0Next number = 5.0, SMA = 3.800Next number = 4.0, SMA = 4.200Next number = 3.0, SMA = 4.200Next number = 2.0, SMA = 3.800Next number = 1.0, SMA = 3.0

Objective-C

#import <Foundation/Foundation.h>@interfaceMovingAverage :NSObject{unsignedintperiod;NSMutableArray*window;doublesum;}-(instancetype)initWithPeriod:(unsignedint)thePeriod;@end@implementationMovingAverage// init with default period-(instancetype)init{self=[superinit];if(self){period=10;window=[[NSMutableArrayalloc]init];sum=0.0;}returnself;}// init with specified period-(instancetype)initWithPeriod:(unsignedint)thePeriod{self=[superinit];if(self){period=thePeriod;window=[[NSMutableArrayalloc]init];sum=0.0;}returnself;}// add a new number to the window-(void)add:(double)val{sum+=val;[windowaddObject:@(val)];if([windowcount]>period){NSNumber*n=window[0];sum-=[ndoubleValue];[windowremoveObjectAtIndex:0];}}// get the average value-(double)avg{if([windowcount]==0){return0;// technically the average is undefined}returnsum/[windowcount];}// set the period, resizes current window-(void)setPeriod:(unsignedint)thePeriod{// make smaller?if(thePeriod<[windowcount]){for(inti=0;i<thePeriod;++i){NSNumber*n=window[0];sum-=[ndoubleValue];[windowremoveObjectAtIndex:0];}}period=thePeriod;}// get the period (window size)-(unsignedint)period{returnperiod;}// clear the window and current sum-(void)clear{[windowremoveAllObjects];sum=0;}@endintmain(intargc,constchar*argv[]){@autoreleasepool{doubletestData[10]={1,2,3,4,5,5,4,3,2,1};intperiods[2]={3,5};for(inti=0;i<2;++i){MovingAverage*ma=[[MovingAveragealloc]initWithPeriod:periods[i]];for(intj=0;j<10;++j){[maadd:testData[j]];NSLog(@"Next number = %f, SMA = %f",testData[j],[maavg]);}NSLog(@"\n");}}return0;}
Output:
Next number = 1.000000, SMA = 1.000000Next number = 2.000000, SMA = 1.500000Next number = 3.000000, SMA = 2.000000Next number = 4.000000, SMA = 3.000000Next number = 5.000000, SMA = 4.000000Next number = 5.000000, SMA = 4.666667Next number = 4.000000, SMA = 4.666667Next number = 3.000000, SMA = 4.000000Next number = 2.000000, SMA = 3.000000Next number = 1.000000, SMA = 2.000000Next number = 1.000000, SMA = 1.000000Next number = 2.000000, SMA = 1.500000Next number = 3.000000, SMA = 2.000000Next number = 4.000000, SMA = 2.500000Next number = 5.000000, SMA = 3.000000Next number = 5.000000, SMA = 3.800000Next number = 4.000000, SMA = 4.200000Next number = 3.000000, SMA = 4.200000Next number = 2.000000, SMA = 3.800000Next number = 1.000000, SMA = 3.000000

OCaml

letsma(n,s,q)x=letl=Queue.lengthqands=s+.xinQueue.pushxq;ifl<nthen(n,s,q),s/.float(l+1)else(lets=s-.Queue.popqin(n,s,q),s/.floatl)let_=letperiodLst=[3;5]inletseries=[1.;2.;3.;4.;5.;5.;4.;3.;2.;1.]inList.iter(fund->Printf.printf"SIMPLE MOVING AVERAGE: PERIOD = %d\n"d;ignore(List.fold_left(funox->leto,m=smaoxinPrintf.printf"Next number = %-2g, SMA = %g\n"xm;o)(d,0.,Queue.create())series;);print_newline();)periodLst
Output:
SIMPLE MOVING AVERAGE: PERIOD = 3Next number = 1 , SMA = 1Next number = 2 , SMA = 1.5Next number = 3 , SMA = 2Next number = 4 , SMA = 3Next number = 5 , SMA = 4Next number = 5 , SMA = 4.66667Next number = 4 , SMA = 4.66667Next number = 3 , SMA = 4Next number = 2 , SMA = 3Next number = 1 , SMA = 2SIMPLE MOVING AVERAGE: PERIOD = 5Next number = 1 , SMA = 1Next number = 2 , SMA = 1.5Next number = 3 , SMA = 2Next number = 4 , SMA = 2.5Next number = 5 , SMA = 3Next number = 5 , SMA = 3.8Next number = 4 , SMA = 4.2Next number = 3 , SMA = 4.2Next number = 2 , SMA = 3.8Next number = 1 , SMA = 3

More imperatively:

letsma_createperiod=letq=Queue.create()andsum=ref0.0infunx->sum:=!sum+.x;Queue.pushxq;ifQueue.lengthq>periodthensum:=!sum-.Queue.popq;!sum/.float(Queue.lengthq)let()=letperiodLst=[3;5]inletseries=[1.;2.;3.;4.;5.;5.;4.;3.;2.;1.]inList.iter(fund->Printf.printf"SIMPLE MOVING AVERAGE: PERIOD = %d\n"d;letsma=sma_createdinList.iter(funx->Printf.printf"Next number = %-2g, SMA = %g\n"x(smax);)series;print_newline();)periodLst

Oforth

createSMA returns a closure.The list of values is included into a channel so this code is thread-safe : multiple tasks running in parallel can call the closure returned.

import: parallel: createSMA(period)| ch |   Channel new [ ] over send drop ->ch   #[ ch receive + left(period) dup avg swap ch send drop ] ;

Usage:

: test| sma3 sma5 l |   3 createSMA -> sma3   5 createSMA -> sma5   [ 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 ] ->l   "SMA3" .cr l apply( #[ sma3 perform . ] ) printcr   "SMA5" .cr l apply( #[ sma5 perform . ] ) ;
Output:
>testSMA31 1.5 2 3 4 4.66666666666667 4.66666666666667 4 3 2SMA51 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3 ok

ooRexx

ooRexx does not have stateful functions, but the same effect can be achieved by using object instances.

testdata=.array~of(1,2,3,4,5,5,4,3,2,1)--runwithdifferentperiodsizesloopperiodover.array~of(3,5)say"Period size ="periodsaymovingaverage=.movingaverage~new(period)loopnumberovertestdataaverage=movingaverage~addnumber(number)say"   Next number ="number", moving average ="averageendsayend::classmovingaverage::methodinitexposeperiodqueuesumusestrictargperiodsum=0--thecircularqueuemakesthiseasyqueue=.circularqueue~new(period)--addanumbertotheaverageset::methodaddNumberexposequeuesumusestrictargnumbersum+=number--addthistothequeueold=queue~queue(number)--ifwepushedanelementofftheendofthequeue,--subtractthisfromoursumifold\=.nilthensum-=old--andreturnthecurrentitemreturnsum/queue~items--extramethodtoretrievecurrentaverage::methodaverageexposequeuesum--undefinedreally,butjustreturn0ifqueue~isemptythenreturn0--returncurrentqueuereturnsum/queue~items
Output:
Period size = 3   Next number = 1, moving average = 1   Next number = 2, moving average = 1.5   Next number = 3, moving average = 2   Next number = 4, moving average = 3   Next number = 5, moving average = 4   Next number = 5, moving average = 4.66666667   Next number = 4, moving average = 4.66666667   Next number = 3, moving average = 4   Next number = 2, moving average = 3   Next number = 1, moving average = 2Period size = 5   Next number = 1, moving average = 1   Next number = 2, moving average = 1.5   Next number = 3, moving average = 2   Next number = 4, moving average = 2.5   Next number = 5, moving average = 3   Next number = 5, moving average = 3.8   Next number = 4, moving average = 4.2   Next number = 3, moving average = 4.2   Next number = 2, moving average = 3.8   Next number = 1, moving average = 3

OxygenBasic

def max 1000Class MovingAverage'==================indexbase 1double average,invperiod,mdata[max]sys    index,periodmethod Setup(double a,p)sys iPeriod=pinvPeriod=1/pindex=0average=afor i=1 to period  mdata[i]=anextend methodmethod Data(double v) as doublesys iindex++if index>period then index=1 'recyclei=index+1 'for oldest dataif i>period then i=1 'recyclemdata[index]=vaverage=average+invperiod*(v-mdata[i])end methodend class'TEST'====MovingAverage AA.Setup 100,10 'initial value and periodA.data 50'...print A.average 'reult 95

Oz

declare  fun {CreateSMA Period}     Xs = {NewCell nil}  in     fun {$ X}        Xs := {List.take X|@Xs Period}                {FoldL @Xs Number.'+' 0.0}        /        {Int.toFloat {Min Period {Length @Xs}}}     end  endin  for Period in [3 5] do     SMA = {CreateSMA Period}  in     {System.showInfo "\nSTART PERIOD "#Period}     for I in 1..5 do        {System.showInfo "  Number = "#I#" , SMA = "#{SMA {Int.toFloat I}}}     end     for I in 5..1;~1 do        {System.showInfo "  Number = "#I#" , SMA = "#{SMA {Int.toFloat I}}}     end  end

PARI/GP

Partial implementation: does not (yet?) create different stores on each invocation.

sma_per(n)={  sma_v=vector(n);  sma_i = 0;  n->if(sma_i++>#sma_v,sma_v[sma_i=1]=n;0,sma_v[sma_i]=n;0)+sum(i=1,#sma_v,sma_v[i])/#sma_v};

Pascal

Works with:Free Pascal

Like in other implementations the sum of the last p values is only updated by subtracting the oldest value and addindg the new. To minimize rounding errors after p values the sum is corrected to the real sum.

programsma;typetsma=recordsmaValue:arrayofdouble;smaAverage,smaSumOld,smaSumNew,smaRezActLength:double;smaActLength,smaLength,smaPos:NativeInt;smaIsntFull:boolean;end;proceduresmaInit(varsma:tsma;p:NativeUint);BeginwithsmadoBeginsetlength(smaValue,0);setlength(smaValue,p);smaLength:=p;smaActLength:=0;smaAverage:=0.0;smaSumOld:=0.0;smaSumNew:=0.0;smaPos:=p-1;smaIsntFull:=trueend;end;functionsmaAddValue(varsma:tsma;v:double):double;BeginwithsmadoBeginIFsmaIsntFullthenBegininc(smaActLength);smaRezActLength:=1/smaActLength;smaIsntFull:=smaActLength<smaLength;end;smaSumOld:=smaSumOld+v-smaValue[smaPos];smaValue[smaPos]:=v;smaSumNew:=smaSumNew+v;smaPos:=smaPos-1;ifsmaPos<0thenbeginsmaSumOld:=smaSumNew;smaSumNew:=0.0;smaPos:=smaLength-1;end;smaAverage:=smaSumOld*smaRezActLength;smaAddValue:=smaAverage;end;end;varsma3,sma5:tsma;i:LongInt;beginsmaInit(sma3,3);smaInit(sma5,5);Fori:=1to5doBeginwrite('Inserting ',i,' into sma3 ',smaAddValue(sma3,i):0:4);writeln(' Inserting ',i,' into sma5 ',smaAddValue(sma5,i):0:4);end;Fori:=5downto1doBeginwrite('Inserting ',i,' into sma3 ',smaAddValue(sma3,i):0:4);writeln(' Inserting ',i,' into sma5 ',smaAddValue(sma5,i):0:4);end;//speed testsmaInit(sma3,3);Fori:=1to100000000dosmaAddValue(sma3,i);writeln('100''000''000 insertions ',sma3.smaAverage:0:4);end.
output
time ./smaInserting 1 into sma3 1.0000 Inserting 1 into sma5 1.0000Inserting 2 into sma3 1.5000 Inserting 2 into sma5 1.5000Inserting 3 into sma3 2.0000 Inserting 3 into sma5 2.0000Inserting 4 into sma3 3.0000 Inserting 4 into sma5 2.5000Inserting 5 into sma3 4.0000 Inserting 5 into sma5 3.0000Inserting 5 into sma3 4.6667 Inserting 5 into sma5 3.8000Inserting 4 into sma3 4.6667 Inserting 4 into sma5 4.2000Inserting 3 into sma3 4.0000 Inserting 3 into sma5 4.2000Inserting 2 into sma3 3.0000 Inserting 2 into sma5 3.8000Inserting 1 into sma3 2.0000 Inserting 1 into sma5 3.0000100'000'000 insertions 99999999.0000real  0m0.780s { 64-Bit }

Perl

Using an initializer function which returns an anonymous closure which closes over an instance(separate for each call to the initializer!) of the lexical variables$period,@list, and$sum:

subsma_generator{my$period=shift;my(@list,$sum);returnsub{my$number=shift;push@list,$number;$sum+=$number;$sum-=shift@listif@list>$period;return$sum/@list;}}# Usage:my$sma=sma_generator(3);for(1,2,3,2,7){printf"append $_ --> sma = %.2f  (with period 3)\n",$sma->($_);}
Output:
append 1 --> sma = 1.00  (with period 3)append 2 --> sma = 1.50  (with period 3)append 3 --> sma = 2.00  (with period 3)append 2 --> sma = 2.33  (with period 3)append 7 --> sma = 4.00  (with period 3)

Phix

withjavascript_semantics-- (optional) put first part in sma.e for encapsulation/reusesequencesma={}-- ((period,history,circnxt))integersma_free=0globalfunctionnew_sma(integerperiod)integerresifsma_freethenres=sma_freesma_free=sma[sma_free]sma[res]={period,{},0}elsesma=append(sma,{period,{},0})res=length(sma)endifreturnresendfunctionglobalprocedureadd_sma(integersidx,atomval)integerperiod,circnxtsequencehistory{period,history,circnxt}=sma[sidx]sma[sidx][2]=0-- (kill refcount)iflength(history)<periodthenhistory=append(history,val)elsecircnxt+=1ifcircnxt>periodthencircnxt=1endifsma[sidx][3]=circnxthistory[circnxt]=valendifsma[sidx][2]=historyendprocedureglobalfunctionget_sma_average(integersidx)sequencehistory=sma[sidx][2]integerl=length(history)returniff(l=0?0:sum(history)/l)endfunctionglobalfunctionmoving_average(integersidx,atomval)add_sma(sidx,val)returnget_sma_average(sidx)endfunctionglobalprocedurefree_sma(integersidx)sma[sidx]=sma_freesma_free=sidxendprocedure--</sma.e>--include sma.econstantsma3=new_sma(3)constantsma5=new_sma(5)printf(1," x  sma3  sma5\n")forxin{1,2,3,4,5,5,4,3,2,1}doatoma3=moving_average(sma3,x),a5=moving_average(sma5,x)printf(1,"%2g %=6.3g %=4.3g\n",{x,a3,a5})endfor
Output:
 x  sma3  sma5 1   1     1 2  1.5   1.5 3   2     2 4   3    2.5 5   4     3 5  4.67  3.8 4  4.67  4.2 3   4    4.2 2   3    3.8 1   2     3

Picat

main =>  L=[1, 2, 3, 4, 5, 5, 4, 3, 2, 1],  Map3 = new_map([p=3]),   Map5 = new_map([p=5]),  foreach(N in L)    printf("n: %-2d sma3: %-17w sma5: %-17w\n",N, sma(N,Map3), sma(N,Map5))  end.sma(N,Map) = Average =>  Stream = Map.get(stream,[]) ++ [N],  if Stream.len > Map.get(p) then    Stream := Stream.tail  end,  Average = cond(Stream.len == 0,                 0,                sum(Stream) / Stream.len),  Map.put(stream,Stream).
Output:
n: 1  sma3: 1.0               sma5: 1.0              n: 2  sma3: 1.5               sma5: 1.5              n: 3  sma3: 2.0               sma5: 2.0              n: 4  sma3: 3.0               sma5: 2.5              n: 5  sma3: 4.0               sma5: 3.0              n: 5  sma3: 4.666666666666667 sma5: 3.8              n: 4  sma3: 4.666666666666667 sma5: 4.2              n: 3  sma3: 4.0               sma5: 4.2              n: 2  sma3: 3.0               sma5: 3.8              n: 1  sma3: 2.0               sma5: 3.0


PicoLisp

(de sma (@Len)   (curry (@Len (Data)) (N)      (push 'Data N)      (and (nth Data @Len) (con @))  # Truncate      (*/ (apply + Data) (length Data)) ) )
(def 'sma3 (sma 3))(def 'sma5 (sma 5))(scl 2)(for N (1.0 2.0 3.0 4.0 5.0 5.0 4.0 3.0 2.0 1.0)   (prinl      (format N *Scl)      "   (sma3) "      (format (sma3 N) *Scl)      "   (sma5) "      (format (sma5 N) *Scl) ) )
Output:
1.00   (sma3) 1.00   (sma5) 1.002.00   (sma3) 1.50   (sma5) 1.503.00   (sma3) 2.00   (sma5) 2.004.00   (sma3) 3.00   (sma5) 2.505.00   (sma3) 4.00   (sma5) 3.005.00   (sma3) 4.67   (sma5) 3.804.00   (sma3) 4.67   (sma5) 4.203.00   (sma3) 4.00   (sma5) 4.202.00   (sma3) 3.00   (sma5) 3.801.00   (sma3) 2.00   (sma5) 3.00

PL/I

version 1

SMA: procedure (N) returns (float byaddr);   declare N fixed;   declare A(*) fixed controlled,           (p, q) fixed binary static initial (0);   if allocation(A) = 0 then signal error;   p = p + 1; if q < 20 then q = q + 1;   if p > hbound(A, 1) then p = 1;   A(p) = N;   return (sum(float(A))/q);I: ENTRY (Period);   declare Period fixed binary;   if allocation(A) > 0 then FREE A;   allocate A(Period);   A = 0;   p = 0;end SMA;

version 2

Translation of:REXX
*process source attributes xref; mat: Proc Options(main); Dcl a(10) Dec Fixed(8,6); Dcl s     Dec Fixed(10,8); Dcl n Bin Fixed(31) init(hbound(a)); /* number of items in the list. */ Dcl p Bin Fixed(31) init(3);         /* the 1st period               */ Dcl q Bin Fixed(31) init(5);         /* the 2nd period               */ Dcl m Bin Fixed(31); Call i(a); Put Edit('            SMA with   SMA with',          '  number    period 3   period 5',          ' --------  ---------- ----------')         (Skip,a); Do m=1 To n;   Put Edit(m,sma(p,m),sma(q,m))(Skip,f(5),2(f(13,6)));   End; i: Proc(a); Dcl a(*) Dec Fixed(8,6); Dcl (j,m) Bin Fixed(31); Do j=1 To hbound(a)/2;   a(j)=j;                            /* ··· increasing values.       */   End; Do k=hbound(a)/2 To 1 By -1;   a(j)=k;                            /* ··· decreasing values.       */   j+=1;   End; End; sma: Proc(p,j) Returns(Dec Fixed(8,6)); Dcl s Dec fixed(8,6) Init(0); Dcl i Bin Fixed(31) Init(0); Dcl j Bin Fixed(31) Init((hbound(a)+1)); Dcl (p,i,k,ka,kb) Bin Fixed(31);   ka=max(1,j-p+1);   kb=j+p;   Do k=ka To kb While(k<=j);     i+=1;     s+=a(k)     End;   s=s/i+0.5e-6;   Return(s); End; End;
Output:
            SMA with   SMA with  number    period 3   period 5 --------  ---------- ----------    1     1.000000     1.000000    2     1.500000     1.500000    3     2.000000     2.000000    4     3.000000     2.500000    5     4.000000     3.000000    6     4.666667     3.800000    7     4.666667     4.200000    8     4.000000     4.200000    9     3.000000     3.800000   10     2.000000     3.000000

Pluto

Translation of:Wren
Library:Pluto-fmt
localfmt=require"fmt"localfunctionsma(period)locali=0localsum=0localstorage={}returnfunction(input)if#storage<periodthensum+=inputstorage:insert(input)endsum+=input-storage[i+1]storage[i+1]=inputi=(i+1)%periodreturnsum/#storageendendlocalsma3=sma(3)localsma5=sma(5)print("  x     sma3   sma5")for{1,2,3,4,5,5,4,3,2,1}asxdofmt.print("%5.3f  %5.3f  %5.3f",x,sma3(x),sma5(x))end
Output:
  x     sma3   sma51.000  1.000  1.0002.000  1.500  1.5003.000  2.000  2.0004.000  3.000  2.5005.000  4.000  3.0005.000  4.667  3.8004.000  4.667  4.2003.000  4.000  4.2002.000  3.000  3.8001.000  2.000  3.000

Pony

classMovingAverageletperiod:USizelet_arr:Array[I32]// circular buffervar_curr:USize// index of pointer positionvar_total:I32// cache the total so farnewcreate(period':USize)=>period=period'_arr=Array[I32](period)// preallocate space_curr=0_total=0funrefapply(n:I32):F32=>_total=_total+nif_arr.size()<periodthen_arr.push(n)elsetryletprev=_arr.update(_curr,n)?_total=_total-prev_curr=(_curr+1)%periodendend_total.f32()/_arr.size().f32()// ---- TESTING -----actorMainnewcreate(env:Env)=>letfoo=MovingAverage(3)letbar=MovingAverage(5)letdata:Array[I32]=[1;2;3;4;5;5;4;3;2;1]forvindata.values()doenv.out.print("Foo: "+foo(v).string())endforvindata.values()doenv.out.print("Bar: "+bar(v).string())end

PowerShell

#This version allows a user to enter numbers one at a time to figure this into the SMA calculations$inputs=@()#Create an array to hold all inputs as they are entered.$period1=3#Define the periods you want to utilize$period2=5Write-host"Enter numbers to observe their moving averages."-ForegroundColorGreenfunctiongetSMA($inputs,[int]$period)#Function takes a array of entered values and a period (3 and 5 in this case){if($inputs.Count-lt$period){$period=$inputs.Count}#Makes sure that if there's less numbers than the designated period (3 in this case), the number of availble values is used as the period instead.for($count=0;$count-lt$period;$count++)#Loop sums the latest available values{$result+=$inputs[($inputs.Count)-$count-1]}return($result|ForEach-Object-begin{$sum=0}-process{$sum+=$_}-end{$sum/$period})#Gets the average for a given period}while($true)#Infinite loop so the user can keep entering numbers{try{$inputs+=[decimal](Read-Host)}catch{Write-Host"Enter only numbers"-ForegroundColorRed}#Enter the numbers. Error checking to help mitigate bad inputs (non-number values)"Added "+$inputs[(($inputs.Count)-1)]+", sma($period1) = "+(getSMA$inputs$Period1)+", sma($period2) = "+(getSMA$inputs$period2)}

PureBasic

Procedure.dSMA(Number,Period=0)StaticPStaticNewListL()ProtectedSum=0IfPeriod<>0P=PeriodEndIfLastElement(L())AddElement(L())L()=NumberWhileListSize(L())>PFirstElement(L())DeleteElement(L(),1)WendForEachL()sum+L()NextProcedureReturnsum/ListSize(L())EndProcedure

Python

Works with:Python version 3.x


Both implementations use thedeque datatype.

Procedural

fromcollectionsimportdequedefsimplemovingaverage(period):assertperiod==int(period)andperiod>0,"Period must be an integer >0"summ=n=0.0values=deque([0.0]*period)# old value queuedefsma(x):nonlocalsumm,nvalues.append(x)summ+=x-values.popleft()n=min(n+1,period)returnsumm/nreturnsma

Class based

fromcollectionsimportdequeclassSimplemovingaverage():def__init__(self,period):assertperiod==int(period)andperiod>0,"Period must be an integer >0"self.period=periodself.stream=deque()def__call__(self,n):stream=self.streamstream.append(n)# appends on the rightstreamlength=len(stream)ifstreamlength>self.period:stream.popleft()streamlength-=1ifstreamlength==0:average=0else:average=sum(stream)/streamlengthreturnaverage

Tests

if__name__=='__main__':forperiodin[3,5]:print("\nSIMPLE MOVING AVERAGE (procedural): PERIOD =",period)sma=simplemovingaverage(period)foriinrange(1,6):print("  Next number =%-2g, SMA =%g "%(i,sma(i)))foriinrange(5,0,-1):print("  Next number =%-2g, SMA =%g "%(i,sma(i)))forperiodin[3,5]:print("\nSIMPLE MOVING AVERAGE (class based): PERIOD =",period)sma=Simplemovingaverage(period)foriinrange(1,6):print("  Next number =%-2g, SMA =%g "%(i,sma(i)))foriinrange(5,0,-1):print("  Next number =%-2g, SMA =%g "%(i,sma(i)))
Output:
SIMPLE MOVING AVERAGE (procedural): 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 (procedural): 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 SIMPLE MOVING AVERAGE (class based): 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 (class based): 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

Quackery

  [ $ "bigrat.qky" loadfile ] now!  [ over size -    space swap of    join ]                 is pad      ( $ n --> $ )  [ ' [ stack [ ] ]    copy nested    ' [ tuck take swap join       dup size ] join    swap join    ' [ > if          [ 1 split nip ]        tuck swap put        0 over witheach +        swap size        dip n->v n->v v/ ]    join copy ]            is make-sma (   n --> [ )                                  ( behaviour of [ is: n --> n/d )  [ stack ]                is sma-3    (     --> s )  3 make-sma sma-3 put  [ stack ]                is sma-5    (     --> s )  5 make-sma sma-5 put  say "n sma-3      sma-5" cr cr  ' [ 1 2 3 4 5 5 4 3 2 1 ]  witheach    [ dup echo sp      dup sma-3 share do      7 point$ 10 pad echo$ sp      sma-5 share do      7 point$ 10 pad echo$ cr ]
Output:
n sma-3      sma-51 1          1         2 1.5        1.5       3 2          2         4 3          2.5       5 4          3         5 4.6666667  3.8       4 4.6666667  4.2       3 4          4.2       2 3          3.8       1 2          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.

#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}})#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 scalarsis.numeric.scalar<-function(x)is.numeric(x)&&length(x)==1Lif(!is.numeric.scalar(latestvalue)||!is.numeric.scalar(len)){stop("all arguments must be numeric scalars")}#Calculate mean of variables so farmean(lastvalues(latestvalue,len))}moving.average(5)# 5moving.average(1)# 3moving.average(-3)# 1moving.average(8)# 2moving.average(7)# 4

Racket

#langracket(requiredata/queue)(define(simple-moving-averageperiod)(definequeue(make-queue))(definesum0.0)(lambda(x)(enqueue!queuex)(set!sum(+sumx))(when(>(queue-lengthqueue)period)(set!sum(-sum(dequeue!queue))))(/sum(queue-lengthqueue))));; Tests(definesma3(simple-moving-average3))(definesma5(simple-moving-average5))(for/lists(lst1lst2)([i'(1234554321)])(values(sma3i)(sma5i)))

Raku

(formerly Perl 6)

Works with:Rakudo version 2016.08
subsma-generator (Int$Pwhere * >0) {sub ($x) {state@a =0xx$P;@a.push($x).shift;@a.sum /$P;    }}# Usage:my&sma =sma-generator3;for1,2,3,2,7 {printf"append $_ --> sma = %.2f  (with period 3)\n",sma$_;}
Output:
append 1 --> sma = 0.33  (with period 3)append 2 --> sma = 1.00  (with period 3)append 3 --> sma = 2.00  (with period 3)append 2 --> sma = 2.33  (with period 3)append 7 --> sma = 4.00  (with period 3)

REXX

The same list of numbers was used as in the  ALGOL68   example.

The 1st and 2nd periods (number of values) were parametrized,   as well as the total number of values.

/*REXX program illustrates and displays a simple moving average using a constructed list*/parseargpqn./*obtain optional arguments from the CL*/ifp==''|p==","thenp=3/*Not specified?  Then use the default.*/ifq==''|q==","thenq=5/* "      "         "   "   "     "    */ifn==''|n==","thenn=10/* "      "         "   "   "     "    */@.=0/*default value, only needed for odd N.*/doj=1forn%2;@.j=j/*build 1st half of list, increasing #s*/end/*j*/dok=n%2by-1to1;@.j=k;j=j+1/*  "   2nd   "   "   "   decreasing " */end/*k*/say'  number  '" SMA with period"p' '" SMA with period"qsay' ──────── '"───────────────────"'───────────────────'pad='     'dom=1forn;saycenter(@.m,10)padleft(SMA(p,m),19)left(SMA(q,m),19)end/*m*/exit/*stick a fork in it,  we're all done. *//*──────────────────────────────────────────────────────────────────────────────────────*/SMA:procedureexpose@.;parseargp,j;i=0;$=0dok=max(1,j-p+1)toj+pforpwhilek<=j;i=i+1;$=$+@.kend/*k*/return$/i/*SMA   ≡   simple moving average.     */
output  when using the generated default input numbers:
  number    SMA with period 3   SMA with period 5 ────────  ─────────────────── ───────────────────    1            1                   1    2            1.5                 1.5    3            2                   2    4            3                   2.5    5            4                   3    5            4.66666667          3.8    4            4.66666667          4.2    3            4                   4.2    2            3                   3.8    1            2                   3

Ring

version 1

load "stdlib.ring"decimals(8)maxperiod = 20nums = newlist(maxperiod,maxperiod)accum = list(maxperiod)index = list(maxperiod)window = list(maxperiod)for i = 1 to maxperiod    index[i] = 1    accum[i] = 0    window[i] = 0nextfor i = 1 to maxperiod    for j = 1 to maxperiod        nums[i][j] = 0    nextnextfor n = 1 to 5    see "number = " + n + "  sma3 = " + left((string(sma(n,3)) + "        "),9) + "  sma5 = " + sma(n,5) + nlnextfor n = 5 to 1 step -1    see "number = " + n + "  sma3 = " + left((string(sma(n,3)) + "        "),9) + "  sma5 = " + sma(n,5) + nlnextsee nl func sma number, period     accum[period] += number - nums[period][index[period]]     nums[period][index[period]] = number     index[period]= (index[period] + 1) % period + 1     if window[period]<period window[period] += 1 ok     return (accum[period] / window[period])

Output:

number = 1  sma3 = 1          sma5 = 1number = 2  sma3 = 1.5000000  sma5 = 1.50000000number = 3  sma3 = 2          sma5 = 2number = 4  sma3 = 3          sma5 = 2.50000000number = 5  sma3 = 4          sma5 = 3number = 5  sma3 = 4.6666666  sma5 = 3.80000000number = 4  sma3 = 4.6666666  sma5 = 4.20000000number = 3  sma3 = 4          sma5 = 4.20000000number = 2  sma3 = 3          sma5 = 3.80000000number = 1  sma3 = 2          sma5 = 3

version 2

load "stdlib.ring"decimals(8)maxperiod = 20nums = newlist(maxperiod,maxperiod)accum = list(maxperiod)index = list(maxperiod)window = list(maxperiod)for i = 1 to maxperiod    index[i] = 1    accum[i] = 0    window[i] = 0nextfor i = 1 to maxperiod    for j = 1 to maxperiod        nums[i][j] = 0    nextnextfor n = 1 to 5    see "number = " + n + "  sma3 = " + left((string(sma(n,3)) + "        "),9) + "  sma5 = " + sma(n,5) + nlnextfor n = 5 to 1 step -1    see "number = " + n + "  sma3 = " + left((string(sma(n,3)) + "        "),9) + "  sma5 = " + sma(n,5) + nlnextsee nl func sma number, periodaccum[period] += number - nums[period][index[period]]nums[period][index[period]] = numberindex[period]= (index[period] + 1) % period + 1if window[period]<period window[period] += 1 okreturn (accum[period] / window[period])

Output:

number = 1  sma3 = 1          sma5 = 1number = 2  sma3 = 1.5000000  sma5 = 1.50000000number = 3  sma3 = 2          sma5 = 2number = 4  sma3 = 3          sma5 = 2.50000000number = 5  sma3 = 4          sma5 = 3number = 5  sma3 = 4.6666666  sma5 = 3.80000000number = 4  sma3 = 4.6666666  sma5 = 4.20000000number = 3  sma3 = 4          sma5 = 4.20000000number = 2  sma3 = 3          sma5 = 3.80000000number = 1  sma3 = 2          sma5 = 3

version 3

### RING: Function Moving Average.   Bert Mariani 2016-06-22###------------------------------### Data array of Google pricesaGOOGPrices = ["658","675","670","664","664","663","663","662","675","693","689","675","636","633","632","607","607","617","617","581","593","570","574","571","575","596","596","601","583","635","587","574","552","531","536","502","488","482","490","503","507","521","534","525","534","559","552","554","555","555","552","579","580","577","575","562","560","559","558","569","573","577","574","559","552","553","560","569","582","579","593","598","593","598","593","586","602","591","594","595","603","614","620","625","635","627","632","631","620","626","616","606","602","659","683","671","670","659","673","679"]###-------------------------------------------------------------### CALL the Function:  MovingAverage  arrayOfPrices timePeriodaGOOGMvgAvg = MovingAverage( aGOOGPrices, 10 )aGOOGMvgAvg = MovingAverage( aGOOGPrices, 30 )###-------------------------------------------------------------### FUNCTION: MovingAverage Func MovingAverage arrayPrices, timePeriod    arrayMvgAvg  = []             ### Output Results to this array    z = len(arrayPrices)          ### array data length                             sumPrices  = 0      ###--------------------------------    ### First MAvg Sum 1 to timePeriod    ###--------------------------------        for i = 1 to  timePeriod                                sumPrices = sumPrices + arrayPrices[i]        mvgAvg    = sumPrices / i        Add( arrayMvgAvg, mvgAvg)       next           ###-----------------------------------------------    ### Second MAvg Sum  timePeriod +1 to End of Data    ###-----------------------------------------------        for i = timePeriod + 1 to z         sumPrices = sumPrices - arrayPrices[i-timePeriod] + arrayPrices[i]         mvgAvg    = sumPrices / timePeriod                                          Add (arrayMvgAvg, mvgAvg    next          return arrayMvgAvg###-------------------------------------------------------------OUTPUT Google Prices moving average using timePeriod = 10Index 88 CurPrice 631 Sum 17735 MvgAvg 591.17Index 89 CurPrice 620 Sum 17797 MvgAvg 593.23Index 90 CurPrice 626 Sum 17854 MvgAvg 595.13Index 91 CurPrice 616 Sum 17897 MvgAvg 596.57Index 92 CurPrice 606 Sum 17926 MvgAvg 597.53Index 93 CurPrice 602 Sum 17954 MvgAvg 598.47Index 94 CurPrice 659 Sum 18054 MvgAvg 601.80Index 95 CurPrice 683 Sum 18185 MvgAvg 606.17Index 96 CurPrice 671 Sum 18303 MvgAvg 610.10Index 97 CurPrice 670 Sum 18413 MvgAvg 613.77Index 98 CurPrice 659 Sum 18503 MvgAvg 616.77Index 99 CurPrice 673 Sum 18594 MvgAvg 619.80Index 100 CurPrice 679 Sum 18694 MvgAvg 623.13###-------------------------------------------------------------

RPL

« IF DUP 0 >THEN 1 →LIST 'SMAPAR' STOELSE "Period must be >0" MSGBOXEND» 'CLRSMA' STO« 'SMAPAR' SWAP STO+SMAPAR TAIL DUP SIZE DUPSMAPAR HEAD - 1 + 0 MAX SWAP SUB SIZE LASTARG 0 + ∑LIST SWAP /»  'SMA' STO
3CLRSMA25SMA 75SMA 100SMA 125SMA
Output:
4: 253: 50 2: 66.66666666671: 100

Ruby

A closure:

defsimple_moving_average(size)nums=[]sum=0.0lambdado|hello|nums<<hellogoodbye=nums.length>size?nums.shift:0sum+=hello-goodbyesum/nums.lengthendendma3=simple_moving_average(3)ma5=simple_moving_average(5)(1.upto(5).to_a+5.downto(1).to_a).eachdo|num|printf"Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n",num,ma3.call(num),ma5.call(num)end

A class

classMovingAveragerdefinitialize(size)@size=size@nums=[]@sum=0.0enddef<<(hello)@nums<<hellogoodbye=@nums.length>@size?@nums.shift:0@sum+=hello-goodbyeselfenddefaverage@sum/@nums.lengthendaliasto_faveragedefto_saverage.to_sendendma3=MovingAverager.new(3)ma5=MovingAverager.new(5)(1.upto(5).to_a+5.downto(1).to_a).eachdo|num|printf"Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n",num,ma3<<num,ma5<<numendend

Run Basic

data 1,2,3,4,5,5,4,3,2,1dim sd(10)                          ' series data global sd                           ' make it global so we all see itfor i = 1 to 10:read sd(i): next ix = sma(3)                          ' simple moving average for 3 periodsx = sma(5)                          ' simple moving average for 5 periodsfunction sma(p)                     ' the simple moving average functionprint "----- SMA:";p;" -----"  for i = 1 to 10    sumSd = 0    for j = max((i - p) + 1,1) to i       sumSd = sumSd + sd(j)         ' sum series data for the period    next j  if p > i then p1 = i else p1 = p  print  sd(i);" sma:";p;" ";sumSd / p1   next iend function
----- SMA:3 -----1 sma:3 12 sma:3 1.53 sma:3 24 sma:3 35 sma:3 45 sma:3 4.66666654 sma:3 4.66666653 sma:3 42 sma:3 31 sma:3 2----- SMA:5 -----1 sma:5 12 sma:5 1.53 sma:5 24 sma:5 2.55 sma:5 35 sma:5 3.799999954 sma:5 4.19999983 sma:5 4.19999982 sma:5 3.799999951 sma:5 3

Rust

Vector Based

structSimpleMovingAverage{period:usize,numbers:Vec<usize>}implSimpleMovingAverage{fnnew(p:usize)->SimpleMovingAverage{SimpleMovingAverage{period:p,numbers:Vec::new()}}fnadd_number(&mutself,number:usize)->f64{self.numbers.push(number);ifself.numbers.len()>self.period{self.numbers.remove(0);}ifself.numbers.is_empty(){return0f64;}else{letsum=self.numbers.iter().fold(0,|acc,x|acc+x);returnsumasf64/self.numbers.len()asf64;}}}fnmain(){forperiodin[3,5].iter(){println!("Moving average with period {}",period);letmutsma=SimpleMovingAverage::new(*period);foriin[1,2,3,4,5,5,4,3,2,1].iter(){println!("Number: {} | Average: {}",i,sma.add_number(*i));}}}

Double-ended Queue Based

usestd::collections::VecDeque;structSimpleMovingAverage{period:usize,numbers:VecDeque<usize>}implSimpleMovingAverage{fnnew(p:usize)->SimpleMovingAverage{SimpleMovingAverage{period:p,numbers:VecDeque::new()}}fnadd_number(&mutself,number:usize)->f64{self.numbers.push_back(number);ifself.numbers.len()>self.period{self.numbers.pop_front();}ifself.numbers.is_empty(){return0f64;}else{letsum=self.numbers.iter().fold(0,|acc,x|acc+x);returnsumasf64/self.numbers.len()asf64;}}}fnmain(){forperiodin[3,5].iter(){println!("Moving average with period {}",period);letmutsma=SimpleMovingAverage::new(*period);foriin[1,2,3,4,5,5,4,3,2,1].iter(){println!("Number: {} | Average: {}",i,sma.add_number(*i));}}}
Moving average with period 3Number: 1 | Average: 1Number: 2 | Average: 1.5Number: 3 | Average: 2Number: 4 | Average: 3Number: 5 | Average: 4Number: 5 | Average: 4.666666666666667Number: 4 | Average: 4.666666666666667Number: 3 | Average: 4Number: 2 | Average: 3Number: 1 | Average: 2Moving average with period 5Number: 1 | Average: 1Number: 2 | Average: 1.5Number: 3 | Average: 2Number: 4 | Average: 2.5Number: 5 | Average: 3Number: 5 | Average: 3.8Number: 4 | Average: 4.2Number: 3 | Average: 4.2Number: 2 | Average: 3.8Number: 1 | Average: 3

Scala

classMovingAverage(period:Int){privatevarqueue=newscala.collection.mutable.Queue[Double]()defapply(n:Double)={queue.enqueue(n)if(queue.size>period)queue.dequeuequeue.sum/queue.size}overridedeftoString=queue.mkString("(",", ",")")+", period "+period+", average "+(queue.sum/queue.size)defclear=queue.clear}
scala> List(3,5) foreach { period =>     |   println("SIMPLE MOVING AVERAGE: PERIOD = "+period)     |   val sma = new MovingAverage(period)     |   1.0 to 5.0 by 1.0 foreach {i => println("  Next number = %-2g, SMA = %g " format (i, sma(i)))}     |   5.0 to 1.0 by -1.0 foreach {i => println("  Next number = %-2g, SMA = %g " format (i, sma(i)))}     |   println(sma+"\n")     | }SIMPLE MOVING AVERAGE: PERIOD = 3  Next number = 1.00000, SMA = 1.00000  Next number = 2.00000, SMA = 1.50000  Next number = 3.00000, SMA = 2.00000  Next number = 4.00000, SMA = 3.00000  Next number = 5.00000, SMA = 4.00000  Next number = 5.00000, SMA = 4.66667  Next number = 4.00000, SMA = 4.66667  Next number = 3.00000, SMA = 4.00000  Next number = 2.00000, SMA = 3.00000  Next number = 1.00000, SMA = 2.00000(3.0, 2.0, 1.0), period 3, average 2.0SIMPLE MOVING AVERAGE: PERIOD = 5  Next number = 1.00000, SMA = 1.00000  Next number = 2.00000, SMA = 1.50000  Next number = 3.00000, SMA = 2.00000  Next number = 4.00000, SMA = 2.50000  Next number = 5.00000, SMA = 3.00000  Next number = 5.00000, SMA = 3.80000  Next number = 4.00000, SMA = 4.20000  Next number = 3.00000, SMA = 4.20000  Next number = 2.00000, SMA = 3.80000  Next number = 1.00000, SMA = 3.00000(5.0, 4.0, 3.0, 2.0, 1.0), period 5, average 3.0

Scheme

(define((simple-moving-averagersize.nums)num)(set!nums(consnum(if(=(lengthnums)size)(reverse(cdr(reversenums)))nums)))(/(apply+nums)(lengthnums)))(defineav(simple-moving-averager3))(mapav'(1234554321))
Output:
(1 3/2 2 3 4 14/3 14/3 4 3 2)

Sidef

Implemented with closures:

funcsimple_moving_average(period){varlist=[]varsum=0func(number){list.append(number)sum+=numberif(list.len>period){sum-=list.shift}(sum/list.length)}}varma3=simple_moving_average(3)varma5=simple_moving_average(5)fornum(1..5,flip(1..5)){printf("Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n",num,ma3.call(num),ma5.call(num))}

Implemented as a class:

classsma_generator(period,list=[],sum=0){methodSMA(number){list.append(number)sum+=numberif(list.len>period){sum-=list.shift}(sum/list.len)}}varma3=sma_generator(3)varma5=sma_generator(5)fornum(1..5,flip(1..5)){printf("Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n",num,ma3.SMA(num),ma5.SMA(num))}
Output:
Next number = 1, SMA_3 = 1.000, SMA_5 = 1.0Next number = 2, SMA_3 = 1.500, SMA_5 = 1.5Next number = 3, SMA_3 = 2.000, SMA_5 = 2.0Next number = 4, SMA_3 = 3.000, SMA_5 = 2.5Next number = 5, SMA_3 = 4.000, SMA_5 = 3.0Next number = 5, SMA_3 = 4.667, SMA_5 = 3.8Next number = 4, SMA_3 = 4.667, SMA_5 = 4.2Next number = 3, SMA_3 = 4.000, SMA_5 = 4.2Next number = 2, SMA_3 = 3.000, SMA_5 = 3.8Next number = 1, SMA_3 = 2.000, SMA_5 = 3.0

Smalltalk

Works with:GNU Smalltalk
Objectsubclass:MovingAverage [|valueCollection period collectedNumber sum|MovingAverageclass>>newWithPeriod:thePeriod [|r|r:=superbasicNew.^rinitWithPeriod:thePeriod    ]initWithPeriod:thePeriod [valueCollection:=OrderedCollectionnew:thePeriod.period:=thePeriod.collectedNumber:=0.sum:=0    ]sma [collectedNumber<periodifTrue: [^sum/collectedNumber ]ifFalse: [^sum/period ] ]add:value [collectedNumber<periodifTrue: [sum:=sum+value.valueCollectionadd:value.collectedNumber:=collectedNumber+1.]ifFalse: [sum:=sum- (valueCollectionremoveFirst).sum:=sum+value.valueCollectionadd:value].^selfsma    ]].
|sma3 sma5|sma3:=MovingAveragenewWithPeriod:3.sma5:=MovingAveragenewWithPeriod:5.#(1234554321)do: [:v|  ('Next number %1, SMA_3 = %2, SMA_5 = %3'% {v. (sma3add:v)asFloat. (sma5add:v)asFloat    })displayNl]

Standard ML

(* helper functions *)valsum=List.foldl(op+)0.0funmeanxs=(sumxs)/(Real.fromInt(lengthxs))typesmastate=int*reallist(* initialize an SMA state with the given period *)funsmaInitperiod:smastate=(period,[])(* update the SMA in the given state with the given number *)(* returns a tuple containing the new SMA and the new state *)funsma(state:smastate)(num:real):(real*smastate)=letval(period,buffer)=statevalamt=Int.min(1+List.lengthbuffer,period)valnewlist=List.take(num::buffer,amt)in(meannewlist,(period,newlist))endfunprintSMA'_[]=()|printSMA'state(x::xs)=letval(n,next)=smastatexinprint("Added "^(Real.toStringx)^": SMA="^(Real.toStringn)^"\n");printSMA'nextxsend(* print the SMA with given period at each step over the list xs *)funprintSMAperiodxs=printSMA'(smaInitperiod)xs
Output:
> printSMA 3 [1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 4.0, 3.0, 2.0, 1.0]);Added 1.0: SMA=1.0Added 2.0: SMA=1.5Added 3.0: SMA=2.0Added 4.0: SMA=3.0Added 5.0: SMA=4.0Added 5.0: SMA=4.66666666667Added 4.0: SMA=4.66666666667Added 3.0: SMA=4.0Added 2.0: SMA=3.0Added 1.0: SMA=2.0val it = (): unit> printSMA 5 (map Real.fromInt [1,2,3,4,5,5,4,3,2,1]);Added 1.0: SMA=1.0Added 2.0: SMA=1.5Added 3.0: SMA=2.0Added 4.0: SMA=2.5Added 5.0: SMA=3.0Added 5.0: SMA=3.8Added 4.0: SMA=4.2Added 3.0: SMA=4.2Added 2.0: SMA=3.8Added 1.0: SMA=3.0val it = (): unit

Swift

Translation of:Rust
structSimpleMovingAverage{varperiod:Intvarnumbers=[Double]()mutatingfuncaddNumber(_n:Double)->Double{numbers.append(n)ifnumbers.count>period{numbers.removeFirst()}guard!numbers.isEmptyelse{return0}returnnumbers.reduce(0,+)/Double(numbers.count)}}forperiodin[3,5]{print("Moving average with period\(period)")varaverager=SimpleMovingAverage(period:period)fornin[1.0,2,3,4,5,5,4,3,2,1]{print("n:\(n); average\(averager.addNumber(n))")}}
Output:
Moving average with period 3n: 1.0; average 1.0n: 2.0; average 1.5n: 3.0; average 2.0n: 4.0; average 3.0n: 5.0; average 4.0n: 5.0; average 4.666666666666667n: 4.0; average 4.666666666666667n: 3.0; average 4.0n: 2.0; average 3.0n: 1.0; average 2.0Moving average with period 5n: 1.0; average 1.0n: 2.0; average 1.5n: 3.0; average 2.0n: 4.0; average 2.5n: 5.0; average 3.0n: 5.0; average 3.8n: 4.0; average 4.2n: 3.0; average 4.2n: 2.0; average 3.8n: 1.0; average 3.0

Tcl

Works with:Tcl version 8.6

or

Library:TclOO
oo::classcreateSimpleMovingAverage{variablevalsidxconstructor{{period3}}{setidxend-[expr{$period-1}]setvals{}}methodvalx{setvals[lrange[list{*}$vals$x]$idxend]expr{[tcl::mathop::+{*}$vals]/double([llength$vals])}}}

Demonstration:

SimpleMovingAveragecreateaverager3SimpleMovingAveragecreateaverager55foreachn{1234554321}{puts"Next number = $n, SMA_3 = [averager3 val $n], SMA_5 = [averager5 val $n]"}
Output:
Next number = 1, SMA_3 = 1.0, SMA_5 = 1.0Next number = 2, SMA_3 = 1.5, SMA_5 = 1.5Next number = 3, SMA_3 = 2.0, SMA_5 = 2.0Next number = 4, SMA_3 = 3.0, SMA_5 = 2.5Next number = 5, SMA_3 = 4.0, SMA_5 = 3.0Next number = 5, SMA_3 = 4.666666666666667, SMA_5 = 3.8Next number = 4, SMA_3 = 4.666666666666667, SMA_5 = 4.2Next number = 3, SMA_3 = 4.0, SMA_5 = 4.2Next number = 2, SMA_3 = 3.0, SMA_5 = 3.8Next number = 1, SMA_3 = 2.0, SMA_5 = 3.0

TI-83 BASIC

Continuously prompts for an inputI, which is added to the end of a listL1. L1 can be found by pressing "2ND"/"1", andmean can be found in "List"/"OPS"

PressON to terminate the program.

:1->C:While 1:Prompt I:C->dim(L1):I->L1(C):Disp mean(L1):1+C->C:End

TI-89 BASIC

Function that returns a list containing the averaged data of the supplied argument

movinavg(list,p)Func  Local r, i, z    For i,1,dim(list)    max(i-p,0)→z    sum(mid(list,z+1,i-z))/(i-z)→r[i]  EndFor  rEndFunc

Program that returns a simple value at each invocation:

movinav2(x_,v_)Prgm  If getType(x_)="STR" Then    {}→list    v_→p    Return  EndIf    right(augment(list,{x_}),p)→list  sum(list)/dim(list)→#v_EndPrgm

Example1: Using the function
movinavg({1,2,3,4,5,6,7,8,9,10},5)

list is the list being averaged: {1,2,3,4,5,6,7,8,9,10}
p is the period: 5
returns the averaged list: {1, 3/2, 2, 5/2, 3, 4, 5, 6, 7, 8}

Example 2: Using the program
movinav2("i",5) - Initializing moving average calculation, and define period of 5
movinav2(3, "x"):x - new data in the list (value 3), and result will be stored on variable x, and displayed
movinav2(4, "x"):x - new data (value 4), and the new result will be stored on variable x, and displayed (4+3)/2
...


Description of the function movinavg:
variable r - is the result (the averaged list) that will be returned
variable i - is the index variable, and it points to the end of the sub-list the list being averaged.
variable z - an helper variable

The function uses variable i to determine which values of the list will be considered in the next average calculation.
At every iteration, variable i points to the last value in the list that will be used in the average calculation.
So we only need to figure out which will be the first value in the list.
Usually we'll have to consider p elements, so the first element will be the one indexed by (i-p+1).
However on the first iterations that calculation will usually be negative, so the following equation will avoid negative indexes: max(i-p+1,1) or, arranging the equation, max(i-p,0)+1.
But the number of elements on the first iterations will also be smaller, the correct value will be (end index - begin index + 1) or, arranging the equation, (i - (max(i-p,0)+1) +1) ,and then, (i-max(i-p,0)).
Variable z holds the common value (max(i-p),0) so the begin_index will be (z+1) and the number_of_elements will be (i-z)

mid(list,z+1, i-z) will return the list of value that will be averaged
sum(...) will sum them
sum(...)/(i-z) → r[i] will average them and store the result in the appropriate place in the result list

VBA

This is a "simple" moving average.

Classsma'to be stored in a class module with name "sma"PrivatenAsInteger'periodPrivatearr()AsDouble'circular listPrivateindexAsInteger'pointer into arrPrivateoldsmaAsDoublePublicSubinit(sizeAsInteger)n=sizeReDimarr(n-1)index=0EndSubPublicFunctionsma(numberAsDouble)AsDoublesma=oldsma+(-arr(index)+number)/noldsma=smaarr(index)=numberindex=(index+1)ModnEndFunctionNormalmodulePublicSubmain()s=[{1,2,3,4,5,5,4,3,2,1}]Dimsma3AsNewsmaDimsma5AsNewsmasma3.init3sma5.init5Fori=1ToUBound(s)Debug.Printi,Format(sma3.sma(CDbl(s(i))),"0.00000"),Debug.PrintFormat(sma5.sma(CDbl(s(i))),"0.00000")NextiEndSub
Output:
 1            0,33333       0,20000 2            1,00000       0,60000 3            2,00000       1,20000 4            3,00000       2,00000 5            4,00000       3,00000 6            4,66667       3,80000 7            4,66667       4,20000 8            4,00000       4,20000 9            3,00000       3,80000 10           2,00000       3,00000

VBScript

data="1,2,3,4,5,5,4,3,2,1"token=Split(data,",")stream=""WScript.StdOut.WriteLine"Number"&vbTab&"SMA3"&vbTab&"SMA5"Forj=LBound(token)ToUBound(token)IfLen(stream)=0Thenstream=token(j)Elsestream=stream&","&token(j)EndIfWScript.StdOut.WriteLinetoken(j)&vbTab&Round(SMA(stream,3),2)&vbTab&Round(SMA(stream,5),2)NextFunctionSMA(s,p)IfLen(s)=0ThenSMA=0ExitFunctionEndIfd=Split(s,",")sum=0IfUBound(d)+1>=pThenc=0Fori=UBound(d)ToLBound(d)Step-1sum=sum+Int(d(i))c=c+1Ifc=pThenExitForEndIfNextSMA=sum/pElseFori=UBound(d)ToLBound(d)Step-1sum=sum+Int(d(i))NextSMA=sum/(UBound(d)+1)EndIfEndFunction
Output:
Number        SMA3        SMA511121.51.5322432.554354.67        3.844.67        4.2344.2233.8123

V (Vlang)

Translation of:Go
fn sma(period int) fn(f64) f64 {    mut i := int(0)    mut sum := f64(0)    mut storage := []f64{len: 0, cap:period}     return fn[mut storage, mut sum, mut i, period](input f64) f64 {        if storage.len < period {            sum += input            storage << input        }         sum += input - storage[i]        storage[i], i = input, (i+1)%period        return sum / f64(storage.len)    }} fn main() {    sma3 := sma(3)    sma5 := sma(5)    println("x       sma3   sma5")    for x in [f64(1), 2, 3, 4, 5, 5, 4, 3, 2, 1] {        println("${x:5.3f}  ${sma3(x):5.3f}  ${sma5(x):5.3f}")    }}
Output:
  x     sma3   sma51.000  1.000  1.0002.000  1.500  1.5003.000  2.000  2.0004.000  3.000  2.5005.000  4.000  3.0005.000  4.667  3.8004.000  4.667  4.2003.000  4.000  4.2002.000  3.000  3.8001.000  2.000  3.000

Wren

Translation of:Go
Library:Wren-fmt
import"./fmt"forFmtvarsma=Fn.new{|period|vari=0varsum=0varstorage=[]returnFn.new{|input|if(storage.count<period){sum=sum+inputstorage.add(input)}sum=sum+input-storage[i]storage[i]=inputi=(i+1)%periodreturnsum/storage.count}}varsma3=sma.call(3)varsma5=sma.call(5)System.print("  x     sma3   sma5")for(xin[1,2,3,4,5,5,4,3,2,1]){Fmt.precision=3Fmt.print("$5f  $5f  $5f",x,sma3.call(x),sma5.call(x))}
Output:
  x     sma3   sma51.000  1.000  1.0002.000  1.500  1.5003.000  2.000  2.0004.000  3.000  2.5005.000  4.000  3.0005.000  4.667  3.8004.000  4.667  4.2003.000  4.000  4.2002.000  3.000  3.8001.000  2.000  3.000

zkl

fcn SMA(P){   fcn(n,ns,P){      sz:=ns.append(n.toFloat()).len();      if(P>sz) return(0.0);      if(P<sz) ns.del(0);      ns.sum(0.0)/P;   }.fp1(List.createLong(P+1),P)  // pre-allocate a list of length P+1}

fp1 creates a partial application fixing the (in this case) the second and thirdparameters

T(1,2,3,4,5,5,4,3,2,1).apply(SMA(3)).println();T(1,2,3,4,5,5,4,3,2,1).apply(SMA(5)).println();
Output:
L(0,0,2,3,4,4.66667,4.66667,4,3,2)L(0,0,0,0,3,3.8,4.2,4.2,3.8,3)
Retrieved from "https://rosettacode.org/wiki/Averages/Simple_moving_average?oldid=392766"
Categories:
Hidden category:
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

[8]ページ先頭

©2009-2026 Movatter.jp