Averages/Simple moving average: Difference between revisions
m (Prob and stats cat) |
(C) |
||
Line 18: | Line 18: | ||
Return sum/n |
Return sum/n |
||
}</lang> |
}</lang> |
||
=={{header|C}}== |
|||
<lang c>#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <stdarg.h> |
|||
typedef struct sma_obj { |
|||
double sma; |
|||
double sum; |
|||
int period; |
|||
double *values; |
|||
int lv; |
|||
} sma_obj_t; |
|||
typedef union sma_result { |
|||
sma_obj_t *handle; |
|||
double sma; |
|||
double *values; |
|||
} sma_result_t; |
|||
enum Action { SMA_NEW, SMA_FREE, SMA_VALUES, SMA_ADD, SMA_MEAN }; |
|||
sma_result_t sma(enum Action action, ...) |
|||
{ |
|||
va_list vl; |
|||
sma_result_t r; |
|||
sma_obj_t *o; |
|||
double v; |
|||
va_start(vl, action); |
|||
switch(action) { |
|||
case SMA_NEW: // args: int period |
|||
r.handle = malloc(sizeof(sma_obj_t)); |
|||
r.handle->sma = 0.0; |
|||
r.handle->period = va_arg(vl, int); |
|||
r.handle->values = malloc(r.handle->period * sizeof(double)); |
|||
r.handle->lv = 0; |
|||
r.handle->sum = 0.0; |
|||
break; |
|||
case SMA_FREE: // args: sma_obj_t *handle |
|||
r.handle = va_arg(vl, sma_obj_t *); |
|||
free(r.handle->values); |
|||
free(r.handle); |
|||
r.handle = NULL; |
|||
break; |
|||
case SMA_VALUES: // args: sma_obj_t *handle |
|||
o = va_arg(vl, sma_obj_t *); |
|||
r.values = o->values; |
|||
break; |
|||
case SMA_MEAN: // args: sma_obj_t *handle |
|||
o = va_arg(vl, sma_obj_t *); |
|||
r.sma = o->sma; |
|||
break; |
|||
case SMA_ADD: // args: sma_obj_t *handle, double value |
|||
o = va_arg(vl, sma_obj_t *); |
|||
v = va_arg(vl, double); |
|||
if ( o->lv < o->period ) { |
|||
o->values[o->lv++] = v; |
|||
o->sum += v; |
|||
o->sma = o->sum / o->lv; |
|||
} else { |
|||
o->sum -= o->values[ o->lv % o->period]; |
|||
o->sum += v; |
|||
o->sma = o->sum / o->period; |
|||
o->values[ o->lv % o->period ] = v; o->lv++; |
|||
} |
|||
r.sma = o->sma; |
|||
break; |
|||
} |
|||
va_end(vl); |
|||
return r; |
|||
}</lang> |
|||
<lang c>double v[] = { 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 }; |
|||
int main() |
|||
{ |
|||
int i; |
|||
sma_obj_t *h3 = sma(SMA_NEW, 3).handle; |
|||
sma_obj_t *h5 = sma(SMA_NEW, 5).handle; |
|||
for(i=0; i < sizeof(v)/sizeof(double) ; i++) { |
|||
printf("next number %lf, SMA_3 = %lf, SMA_5 = %lf\n", |
|||
v[i], sma(SMA_ADD, h3, v[i]).sma, sma(SMA_ADD, h5, v[i]).sma); |
|||
} |
|||
sma(SMA_FREE, h3); |
|||
sma(SMA_FREE, h5); |
|||
return 0; |
|||
}</lang> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
Revision as of 20:48, 22 June 2009
You are encouraged to solve this task according to the task description, using any language you may know.
Computing the simple moving average of a series of numbers.
Create a stateful function/class/instance that takes a number as argument and returns a simple moving average of its arguments so far.
AutoHotkey
ahk forum: discussion <lang AutoHotkey>MsgBox % MovingAverage() ; reset: blank MsgBox % MovingAverage(1) ; 1 MsgBox % MovingAverage(3) ; 2 MsgBox % MovingAverage(-1) ; 1
MovingAverage(x="") {
Static sum:=0, n:=0 If (x="") ; blank parameter: reset sum := 0, n := 0 Else sum += x, n++ ; update state Return sum/n
}</lang>
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <stdarg.h>
typedef struct sma_obj {
double sma; double sum; int period; double *values; int lv;
} sma_obj_t;
typedef union sma_result {
sma_obj_t *handle; double sma; double *values;
} sma_result_t;
enum Action { SMA_NEW, SMA_FREE, SMA_VALUES, SMA_ADD, SMA_MEAN }; sma_result_t sma(enum Action action, ...) {
va_list vl; sma_result_t r; sma_obj_t *o; double v;
va_start(vl, action); switch(action) { case SMA_NEW: // args: int period r.handle = malloc(sizeof(sma_obj_t)); r.handle->sma = 0.0; r.handle->period = va_arg(vl, int); r.handle->values = malloc(r.handle->period * sizeof(double)); r.handle->lv = 0; r.handle->sum = 0.0; break; case SMA_FREE: // args: sma_obj_t *handle r.handle = va_arg(vl, sma_obj_t *); free(r.handle->values); free(r.handle); r.handle = NULL; break; case SMA_VALUES: // args: sma_obj_t *handle o = va_arg(vl, sma_obj_t *); r.values = o->values; break; case SMA_MEAN: // args: sma_obj_t *handle o = va_arg(vl, sma_obj_t *); r.sma = o->sma; break; case SMA_ADD: // args: sma_obj_t *handle, double value o = va_arg(vl, sma_obj_t *); v = va_arg(vl, double); if ( o->lv < o->period ) { o->values[o->lv++] = v; o->sum += v; o->sma = o->sum / o->lv; } else { o->sum -= o->values[ o->lv % o->period]; o->sum += v; o->sma = o->sum / o->period; o->values[ o->lv % o->period ] = v; o->lv++; } r.sma = o->sma; break; } va_end(vl); return r;
}</lang>
<lang c>double v[] = { 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 };
int main() {
int i;
sma_obj_t *h3 = sma(SMA_NEW, 3).handle; sma_obj_t *h5 = sma(SMA_NEW, 5).handle;
for(i=0; i < sizeof(v)/sizeof(double) ; i++) { printf("next number %lf, SMA_3 = %lf, SMA_5 = %lf\n",
v[i], sma(SMA_ADD, h3, v[i]).sma, sma(SMA_ADD, h5, v[i]).sma);
}
sma(SMA_FREE, h3); sma(SMA_FREE, h5); return 0;
}</lang>
Common Lisp
This implementation uses a circular list to store the numbers within the window; at the beginning of each iteration pointer refers to the list cell which holds the value just moving out of the window and to be replaced with the just-added value.
<lang lisp>(defun simple-moving-average (period &aux
(sum 0) (count 0) (values (make-list period)) (pointer values)) (setf (rest (last values)) values) ; construct circularity (lambda (n) (when (first pointer) (decf sum (first pointer))) ; subtract old value (incf sum n) ; add new value (incf count) (setf (first pointer) n) (setf pointer (rest pointer)) ; advance pointer (/ sum (min count period))))</lang>
Forth
<lang forth>
- f+! ( f addr -- ) dup f@ f+ f! ;
- ,f0s ( n -- ) falign 0 do 0e f, loop ;
- period @ ;
- used cell+ ;
- head 2 cells + ;
- sum 3 cells + faligned ;
- ring ( addr -- faddr )
dup sum float+ swap head @ floats + ;
- update ( fvalue addr -- addr )
dup ring f@ fnegate dup sum f+! fdup dup ring f! dup sum f+! dup head @ 1+ over period mod over head ! ;
- moving-average
create ( period -- ) dup , 0 , 0 , 1+ ,f0s does> ( fvalue -- avg ) update dup used @ over period < if 1 over used +! then dup sum f@ used @ 0 d>f f/ ;
3 moving-average sma 1e sma f. \ 1. 2e sma f. \ 1.5 3e sma f. \ 2. 4e sma f. \ 3. </lang>
Perl
<lang perl>sub sma ($)
{my ($period, $sum, @a) = shift, 0; return sub {unshift @a, shift; $sum += $a[0]; @a > $period and $sum -= pop @a; return $sum / @a;}}</lang>
Python
<lang python>def simplemovingaverage(period):
assert period == int(period) and period > 0, "Period must be an integer >0" summ = n = 0.0 values = [0.0] * period # old value queue
def sma(x): nonlocal summ, n, values n += 1 values.insert(0, x) summ += x - values.pop() n = n if n <= period else period return summ / n
return sma
if __name__ == '__main__':
for period in [3, 5]: print ("\nSIMPLE MOVING AVERAGE: PERIOD =", period) sma = simplemovingaverage(period) for i in range(1,6): print (" Next number = %-2g, SMA = %g " % (i, sma(i))) for i in range(5, 0, -1): print (" Next number = %-2g, SMA = %g " % (i, sma(i)))</lang>
Sample output
SIMPLE MOVING AVERAGE: PERIOD = 3 Next number = 1 , SMA = 1 Next number = 2 , SMA = 1.5 Next number = 3 , SMA = 2 Next number = 4 , SMA = 3 Next number = 5 , SMA = 4 Next number = 5 , SMA = 4.66667 Next number = 4 , SMA = 4.66667 Next number = 3 , SMA = 4 Next number = 2 , SMA = 3 Next number = 1 , SMA = 2 SIMPLE MOVING AVERAGE: PERIOD = 5 Next number = 1 , SMA = 1 Next number = 2 , SMA = 1.5 Next number = 3 , SMA = 2 Next number = 4 , SMA = 2.5 Next number = 5 , SMA = 3 Next number = 5 , SMA = 3.8 Next number = 4 , SMA = 4.2 Next number = 3 , SMA = 4.2 Next number = 2 , SMA = 3.8 Next number = 1 , SMA = 3
Ruby
A closure: <lang ruby>def simple_moving_average(size)
nums = [] sum = 0.0 lambda do |hello| nums << hello goodbye = nums.length > size ? nums.shift : 0 sum += hello - goodbye sum / nums.length end
end
ma3 = simple_moving_average(3) ma5 = simple_moving_average(5)
(1.upto(5).to_a + 5.downto(1).to_a).each do |num|
printf "Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n", num, ma3.call(num), ma5.call(num)
end</lang>
A class <lang ruby>class MovingAverager
def initialize(size) @size = size @nums = [] @sum = 0.0 end def <<(hello) @nums << hello goodbye = @nums.length > @size ? @nums.shift : 0 @sum += hello - goodbye self end def average @sum / @nums.length end alias to_f average def to_s average.to_s end
end
ma3 = MovingAverager.new(3) ma5 = MovingAverager.new(5)
(1.upto(5).to_a + 5.downto(1).to_a).each do |num|
printf "Next number = %d, SMA_3 = %.3f, SMA_5 = %.1f\n", num, ma3 << num, ma5 <<num
end</lang>
Tcl
<lang tcl>oo::class create SimpleMovingAverage {
variable vals idx constructor Template:Period 3 { set idx end-[expr {$period-1}] set vals {} } method val x { set vals [lrange [list {*}$vals $x] $idx end] expr {[tcl::mathop::+ {*}$vals]/double([llength $vals])} }
}</lang> Demonstration: <lang tcl>SimpleMovingAverage create averager3 SimpleMovingAverage create averager5 5 foreach n {1 2 3 4 5 5 4 3 2 1} {
puts "Next number = $n, SMA_3 = [averager3 val $n], SMA_5 = [averager5 val $n]"
}</lang> Output:
Next number = 1, SMA_3 = 1.0, SMA_5 = 1.0 Next number = 2, SMA_3 = 1.5, SMA_5 = 1.5 Next number = 3, SMA_3 = 2.0, SMA_5 = 2.0 Next number = 4, SMA_3 = 3.0, SMA_5 = 2.5 Next number = 5, SMA_3 = 4.0, SMA_5 = 3.0 Next number = 5, SMA_3 = 4.666666666666667, SMA_5 = 3.8 Next number = 4, SMA_3 = 4.666666666666667, SMA_5 = 4.2 Next number = 3, SMA_3 = 4.0, SMA_5 = 4.2 Next number = 2, SMA_3 = 3.0, SMA_5 = 3.8 Next number = 1, SMA_3 = 2.0, SMA_5 = 3.0