2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,18 +1,23 @@
Computing the [[wp:Moving_average#Simple_moving_average|simple moving average]] of a series of numbers.
The task is to:
:''Create a [[wp:Stateful|stateful]] 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.''
{{task heading}}
'''Description'''<br>
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().
Create a [[wp:Stateful|stateful]] 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.
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.
{{task heading|Description}}
Pseudocode for an implementation of SMA is:
A simple moving average is a method for computing an average of a stream of numbers by only averaging the last &nbsp; P &nbsp; numbers from the stream, &nbsp; where &nbsp; P &nbsp; is known as the period.
It can be implemented by calling an initialing routine with &nbsp; P &nbsp; as its argument, &nbsp; I(P), &nbsp; 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 &nbsp; P &nbsp; of them, lets call this &nbsp; SMA().
The word &nbsp; ''stateful'' &nbsp; in the task description refers to the need for &nbsp; SMA() &nbsp; to remember certain information between calls to it:
* &nbsp; The period, &nbsp; P
* &nbsp; An ordered container of at least the last &nbsp; P &nbsp; numbers from each of its individual calls.
<br>
''Stateful'' &nbsp; also means that successive calls to &nbsp; I(), &nbsp; the initializer, &nbsp; should return separate routines that do &nbsp; ''not'' &nbsp; share saved state so they could be used on two independent streams of data.
Pseudo-code for an implementation of &nbsp; SMA &nbsp; is:
<pre>
function SMA(number: N):
stateful integer: P
@ -30,5 +35,8 @@ function SMA(number: N):
return average
</pre>
{{task heading|See also}}
See also: [[Standard Deviation]]
{{Related tasks/Statistical measures}}
<hr>

View file

@ -0,0 +1,42 @@
$ cat simple-moving-avg.exs
#!/usr/bin/env elixir
defmodule Math do
def average([]), do: nil
def average(enum) do
Enum.sum(enum) / length(enum)
end
end
defmodule SMA do
def sma(l, p \\ 10) do
IO.puts("\nSimple moving average(period=#{p}):")
Enum.chunk(l, p, 1)
|> Enum.map(&(%{"input": &1, "avg": Float.round(Math.average(&1), 3)}))
end
defmacro gen_func(p) do
quote do
fn l -> SMA.sma(l, unquote(p)) end
end
end
def read_numeric_input do
IO.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)))
end
def run do
sma_func_10 = gen_func(10)
sma_func_15 = gen_func(15)
numbers = read_numeric_input
sma_func_10.(numbers) |> IO.inspect
sma_func_15.(numbers) |> IO.inspect
end
end
SMA.run

View file

@ -0,0 +1,5 @@
#!/bin/bash
elixir ./simple-moving-avg.exs <<EOF
1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1
2 4 6 8 10 12 14 12 10 8 6 4 2
EOF

View file

@ -1,26 +1,25 @@
{-# LANGUAGE BangPatterns #-}
import Control.Monad
import Data.List
import Data.IORef
data Pair a b = Pair !a !b
mean :: Fractional a => [a] -> a
mean xs = sum xs / (genericLength xs)
mean = divl . foldl' (\(Pair s l) x -> Pair (s+x) (l+1)) (Pair 0.0 0)
where divl (_,0) = 0.0
divl (s,l) = s / fromIntegral l
series = [1,2,3,4,5,5,4,3,2,1]
simple_moving_averager period = do
numsRef <- newIORef []
return (\x -> do
nums <- readIORef numsRef
let xs = take period (x:nums)
writeIORef numsRef xs
return $ mean xs
)
mkSMA :: Int -> IO (Double -> IO Double)
mkSMA period = avgr <$> newIORef []
where avgr nsref x = readIORef nsref >>= (\ns ->
let xs = take period (x:ns)
in writeIORef nsref xs $> mean xs)
main = do
sma3 <- simple_moving_averager 3
sma5 <- simple_moving_averager 5
forM_ series (\n -> do
mm3 <- sma3 n
mm5 <- sma5 n
putStrLn $ "Next number = " ++ (show n) ++ ", SMA_3 = " ++ (show mm3) ++ ", SMA_5 = " ++ (show mm5)
)
main = mkSMA 3 >>= (\sma3 -> mkSMA 5 >>= (\sma5 ->
mapM_ (str <$> pure n <*> sma3 <*> sma5) series))
where str n mm3 mm5 =
concat ["Next number = ",show n,", SMA_3 = ",show mm3,", SMA_5 = ",show mm5]

View file

@ -23,6 +23,4 @@ demostrateSMA :: State SMAState [Float]
demostrateSMA = mapM computeSMA [1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
main :: IO ()
main = putStrLn $ (show result)
where
(result, _) = runState demostrateSMA []
main = print $ evalState demostrateSMA []

View file

@ -1,10 +1,19 @@
// single-sided
Array.prototype.simpleSMA=function(N) {
return this.map(function(x,i,v) {
if(i<N-1) return NaN;
return v.filter(function(x2,i2) { return i2<=i && i2>i-N; }).reduce(function(a,b){ return a+b; })/N;
}); };
return this.map(
function(el,index, _arr) {
return _arr.filter(
function(x2,i2) {
return i2 <= index && i2 > index - N;
})
.reduce(
function(current, last, index, arr){
return (current + last);
})/index || 1;
});
};
g=[1,2,3,4,5,8,5,4];
console.log(g.simpleSMA(3))
console.log(g.simpleSMA(5))
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));

View file

@ -0,0 +1,9 @@
v:v,|v:1+!5
v
1 2 3 4 5 5 4 3 2 1
avg:{(+/x)%#x}
sma:{avg'x@(,\!y),(1+!y)+\:!y}
sma[v;5]
1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3

View file

@ -0,0 +1,4 @@
sma:{n::x#_n; {n::1_ n,x; {avg x@&~_n~'x} n}}
sma[5]' v
1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3

View file

@ -1,10 +1,19 @@
do
local t = {}
function f(a, b, ...) if b then return f(a+b, ...) else return a end end
function average(n)
if #t == 10 then table.remove(t, 1) end
t[#t + 1] = n
return f(unpack(t)) / #t
end
function sma(period)
local t = {}
function sum(a, ...)
if a then return a+sum(...) else return 0 end
end
function average(n)
if #t == period then table.remove(t, 1) end
t[#t + 1] = n
return sum(unpack(t)) / #t
end
return average
end
for v=1,30 do print(average(v)) end
sma5 = sma(5)
sma10 = sma(10)
print("SMA 5")
for v=1,15 do print(sma5(v)) end
print("\nSMA 10")
for v=1,15 do print(sma10(v)) end

View file

@ -0,0 +1,7 @@
sub sma-generator (Int $P where * > 0) {
sub ($x) {
state @a = 0 xx $P;
@a.push($x).shift;
@a.sum / $P;
}
}

View file

@ -0,0 +1,5 @@
my &sma = sma-generator 3;
for 1, 2, 3, 2, 7 {
printf "append $_ --> sma = %.2f (with period 3)\n", sma $_;
}

View file

@ -1,7 +0,0 @@
sub sma(Int \P where * > 0) returns Sub {
sub ($x) {
state @a = 0 xx P;
@a.push($x).shift;
P R/ [+] @a;
}
}

View file

@ -1,26 +1,19 @@
/*REXX program illustrates simple moving average using a constructed list. */
parse arg p q n . /*get optional arguments from the C.L. */
if p=='' then p=3 /*the 1st period (the default is: 3).*/
if q=='' then q=5 /* " 2nd " " " " 5).*/
if n=='' then n=10 /*the number of items in the list. */
@.=0 /*define array with initial zero values*/
/* [↓] build 1st half of list*/
do j=1 for n%2; @.j=j; end /* ··· increasing values.*/
/* [↓] build 2nd half of list*/
do k=n%2 to 1 by -1; @.j=k; j=j+1; end /* ··· decreasing values.*/
/*REXX program illustrates and displays a simple moving average using a constructed list*/
parse arg p q n . /*obtain optional arguments from the CL*/
if p=='' | p=="," then p= 3 /*Not specified? Then use the default.*/
if q=='' | q=="," then q= 5 /* " " " " " " */
if n=='' | n=="," then n=10 /* " " " " " " */
@.=0 /*default value, only needed for odd N.*/
do j=1 for n%2; @.j=j; end /*build 1st half of list, increasing #s*/
do k=n%2 by -1 to 1; @.j=k; j=j+1; end /* " 2nd " " " decreasing " */
say ' ' " SMA with " ' SMA with '
say ' number ' " period" p' ' ' period' q
say ' ' "──────────" ''
say ' ' " SMA with " ' SMA with '
say ' number ' " period" p' ' ' period' q
say ' ' "──────────" ''
/* [↓] perform a simple moving average*/
do m=1 for n
say center(@.m, 10) left(sma(p,m), 11) left(sma(q,m), 11)
end /*m*/ /* [↑] show a simple moving average.*/
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
sma: procedure expose @.; parse arg p,j; s=0; i=0
do k=max(1,j-p+1) to j+p for p while k<=j; i=i+1
s=s+@.k
end /*k*/
return s/i
do m=1 for n; say center(@.m, 10) left(SMA(p, m), 11) left(SMA(q, m), 11); end
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
SMA: procedure expose @.; parse arg p,j; i=0 ; $=0
do k=max(1, j-p+1) to j+p for p while k<=j; i=i+1; $=$+@.k; end
return $/i

View file

@ -0,0 +1,39 @@
struct SimpleMovingAverage {
period: usize,
numbers: Vec<usize>
}
impl SimpleMovingAverage {
fn new(p: usize) -> SimpleMovingAverage {
SimpleMovingAverage {
period: p,
numbers: Vec::new()
}
}
fn add_number(&mut self, number: usize) -> f64 {
self.numbers.push(number);
if self.numbers.len() > self.period {
self.numbers.remove(0);
}
if self.numbers.is_empty() {
return 0f64;
}else {
let sum = self.numbers.iter().fold(0, |acc, x| acc+x);
return sum as f64 / self.numbers.len() as f64;
}
}
}
fn main() {
for period in [3, 5].iter() {
println!("Moving average with period {}", period);
let mut sma = SimpleMovingAverage::new(*period);
for i in [1, 2, 3, 4, 5, 5, 4, 3, 2, 1].iter() {
println!("Number: {} | Average: {}", i, sma.add_number(*i));
}
}
}

View file

@ -0,0 +1,41 @@
use std::collections::VecDeque;
struct SimpleMovingAverage {
period: usize,
numbers: VecDeque<usize>
}
impl SimpleMovingAverage {
fn new(p: usize) -> SimpleMovingAverage {
SimpleMovingAverage {
period: p,
numbers: VecDeque::new()
}
}
fn add_number(&mut self, number: usize) -> f64 {
self.numbers.push_back(number);
if self.numbers.len() > self.period {
self.numbers.pop_front();
}
if self.numbers.is_empty() {
return 0f64;
}else {
let sum = self.numbers.iter().fold(0, |acc, x| acc+x);
return sum as f64 / self.numbers.len() as f64;
}
}
}
fn main() {
for period in [3, 5].iter() {
println!("Moving average with period {}", period);
let mut sma = SimpleMovingAverage::new(*period);
for i in [1, 2, 3, 4, 5, 5, 4, 3, 2, 1].iter() {
println!("Number: {} | Average: {}", i, sma.add_number(*i));
}
}
}

View file

@ -0,0 +1,37 @@
data = "1,2,3,4,5,5,4,3,2,1"
token = Split(data,",")
stream = ""
WScript.StdOut.WriteLine "Number" & vbTab & "SMA3" & vbTab & "SMA5"
For j = LBound(token) To UBound(token)
If Len(stream) = 0 Then
stream = token(j)
Else
stream = stream & "," & token(j)
End If
WScript.StdOut.WriteLine token(j) & vbTab & Round(SMA(stream,3),2) & vbTab & Round(SMA(stream,5),2)
Next
Function SMA(s,p)
If Len(s) = 0 Then
SMA = 0
Exit Function
End If
d = Split(s,",")
sum = 0
If UBound(d) + 1 >= p Then
c = 0
For i = UBound(d) To LBound(d) Step -1
sum = sum + Int(d(i))
c = c + 1
If c = p Then
Exit For
End If
Next
SMA = sum / p
Else
For i = UBound(d) To LBound(d) Step -1
sum = sum + Int(d(i))
Next
SMA = sum / (UBound(d) + 1)
End If
End Function