Averages/Simple moving average: Difference between revisions
(→{{header|Ruby}}: as per the wikipedia page, keep the running sum) |
Underscore (talk | contribs) (Added Perl.) |
||
Line 3: | Line 3: | ||
Create a [[wp:Stateful|stateful]] function/class/instance that takes a number as argument and returns a simple moving average of its arguments so far. |
Create a [[wp:Stateful|stateful]] function/class/instance that takes a number as argument and returns a simple moving average of its arguments so far. |
||
=={{header|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> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
Revision as of 17:43, 18 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.
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