1// Copyright (c) 2014 Couchbase, Inc.
2// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
3// except in compliance with the License. You may obtain a copy of the License at
4//   http://www.apache.org/licenses/LICENSE-2.0
5// Unless required by applicable law or agreed to in writing, software distributed under the
6// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
7// either express or implied. See the License for the specific language governing permissions
8// and limitations under the License.
9package common
10
11import (
12	"math"
13)
14
15type Sample struct {
16	size  int
17	count int
18
19	buf  []float64
20	head int // pos of head of buf
21	free int // pos of head of free list
22}
23
24//
25// Constructor
26//
27func NewSample(size int) *Sample {
28
29	s := &Sample{
30		size: size,
31		buf:  make([]float64, size),
32	}
33	return s
34}
35
36//
37// Add a new value to the sample.
38//
39func (s *Sample) Update(v float64) {
40
41	if s.count == s.size {
42		s.pop()
43	}
44
45	next := s.free + 1
46	if next >= s.size {
47		next = 0
48	}
49
50	s.buf[s.free] = v
51	s.free = next
52	s.count++
53}
54
55//
56// Free the oldest sample
57//
58func (s *Sample) pop() {
59
60	if s.count > 0 {
61		next := s.head + 1
62		if next >= s.size {
63			next = 0
64		}
65
66		s.head = next
67		s.count--
68	}
69}
70
71//
72// Calcuate Mean
73//
74func (s *Sample) Mean() float64 {
75
76	return s.WindowMean(s.count)
77}
78
79//
80// Calcuate Mean of a custom window size
81//
82func (s *Sample) WindowMean(count int) float64 {
83
84	if s.count == 0 {
85		return 0
86	}
87
88	if count > s.count {
89		count = s.count
90	}
91
92	total := float64(0)
93
94	tail := s.free - 1
95	for i := 0; i < count; i++ {
96		if tail < 0 {
97			tail = s.size - 1
98		}
99
100		total += s.buf[tail]
101		tail--
102	}
103
104	return total / float64(count)
105}
106
107//
108// Calcuate Std Dev
109//
110func (s *Sample) StdDev() float64 {
111
112	return s.WindowStdDev(s.count)
113}
114
115//
116// Calcuate Std Dev on a custom window size
117//
118func (s *Sample) WindowStdDev(count int) float64 {
119
120	if s.count == 0 {
121		return 0
122	}
123
124	if count > s.count {
125		count = s.count
126	}
127
128	mean := s.WindowMean(count)
129	variance := float64(0)
130
131	tail := s.free - 1
132	for i := 0; i < count; i++ {
133		if tail < 0 {
134			tail = s.size - 1
135		}
136
137		v := s.buf[tail] - mean
138		variance += v * v
139		tail--
140	}
141
142	variance = variance / float64(count)
143	return math.Sqrt(variance)
144}
145
146//
147// Return last value
148//
149func (s *Sample) Last() float64 {
150
151	if s.count == 0 {
152		return 0
153	}
154
155	tail := s.free - 1
156	if tail < 0 {
157		tail = s.size - 1
158	}
159
160	return s.buf[tail]
161}
162
163//
164// Return number of samples
165//
166func (s *Sample) Count() int {
167	return s.count
168}
169