diff --git a/utilities/runAvg/runAvg.go b/utilities/runAvg/runAvg.go new file mode 100644 index 0000000..b0de3fd --- /dev/null +++ b/utilities/runAvg/runAvg.go @@ -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 +} \ No newline at end of file