Generic running average calculator.
This commit is contained in:
parent
1321010d6f
commit
59b8303aaf
1 changed files with 78 additions and 0 deletions
78
utilities/runAvg/runAvg.go
Normal file
78
utilities/runAvg/runAvg.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
A utility to calculate the running average.
|
||||||
|
|
||||||
|
One should implement Val() to be able to use this utility.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package runAvg
|
||||||
|
|
||||||
|
import "container/list"
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
// Value to use for running average calculation.
|
||||||
|
Val() float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type runningAverageCalculator struct {
|
||||||
|
window list.List
|
||||||
|
windowSize int
|
||||||
|
currentSum float64
|
||||||
|
numberOfElementsInWindow int
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleton instance
|
||||||
|
var racSingleton *runningAverageCalculator
|
||||||
|
|
||||||
|
// return single instance
|
||||||
|
func getInstance(curSum float64, n int, wSize int) *runningAverageCalculator {
|
||||||
|
if racSingleton == nil {
|
||||||
|
racSingleton = &runningAverageCalculator {
|
||||||
|
windowSize: wSize,
|
||||||
|
currentSum: curSum,
|
||||||
|
numberOfElementsInWindow: n,
|
||||||
|
}
|
||||||
|
return racSingleton
|
||||||
|
} else {
|
||||||
|
// Updating window size if a new window size is given.
|
||||||
|
if wSize != racSingleton.windowSize {
|
||||||
|
racSingleton.windowSize = wSize
|
||||||
|
}
|
||||||
|
return racSingleton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the running average by adding 'data' to the window.
|
||||||
|
// Updating currentSum to get constant time complexity for every running average computation.
|
||||||
|
func (rac *runningAverageCalculator) calculate(data Interface) float64 {
|
||||||
|
if rac.numberOfElementsInWindow < rac.windowSize {
|
||||||
|
rac.window.PushBack(data)
|
||||||
|
rac.numberOfElementsInWindow++
|
||||||
|
rac.currentSum += data.Val()
|
||||||
|
} else {
|
||||||
|
// removing the element at the front of the window.
|
||||||
|
elementToRemove := rac.window.Front()
|
||||||
|
rac.currentSum -= elementToRemove.Value.(Interface).Val()
|
||||||
|
rac.window.Remove(elementToRemove)
|
||||||
|
|
||||||
|
// adding new element to the window
|
||||||
|
rac.window.PushBack(data)
|
||||||
|
rac.currentSum += data.Val()
|
||||||
|
}
|
||||||
|
return rac.currentSum / float64(rac.window.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taking windowSize as a parameter to allow for sliding window implementation.
|
||||||
|
func Calc(data Interface, windowSize int) float64 {
|
||||||
|
rac := getInstance(0.0, 0, windowSize)
|
||||||
|
return rac.calculate(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the parameters of the running average calculator
|
||||||
|
func Init() {
|
||||||
|
// Setting parameters to default values. Could also set racSingleton to nil but this leads to unnecessary overhead of creating
|
||||||
|
// another instance when Calc is called.
|
||||||
|
racSingleton.window.Init()
|
||||||
|
racSingleton.windowSize = 0
|
||||||
|
racSingleton.currentSum = 0.0
|
||||||
|
racSingleton.numberOfElementsInWindow = 0
|
||||||
|
}
|
Reference in a new issue