-
Notifications
You must be signed in to change notification settings - Fork 0
/
stats.go
71 lines (61 loc) · 2.07 KB
/
stats.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package adaptivepool
import "math"
// Stats efficiently computes a set of statistical values of numbers pushed to
// it, with high precision, and without the need to store all the values.
type Stats struct {
n, actualN, maxN float64
oldM, newM float64
oldS, newS float64
}
// Push adds a new value to the sample.
func (s *Stats) Push(v float64) {
if s.n < s.maxN || s.maxN < 1 {
s.n++
}
if s.actualN++; s.actualN > 1 {
s.newM = math.FMA(s.oldM, s.n-1, v) / s.n
s.newS = math.FMA(math.Abs(v-s.oldM), math.Abs(v-s.newM), s.oldS)
s.oldM = s.newM
s.oldS = s.newS
} else {
s.oldM = v
s.newM = v
}
}
// Reset clears all the data.
func (s *Stats) Reset() { *s = Stats{} }
// N returns the number of pushed values.
func (s *Stats) N() float64 { return s.n }
// MaxN returns the maximum value of N. See [*Stats.SetMaxN] for details.
func (s *Stats) MaxN() float64 { return math.Round(s.maxN) }
// SetMaxN will prevent the value of N (the number of observations) from being
// incremented beyond `maxN`. This is useful to keep a bias towards latest
// values, improving the adaptability to seasonal changes in data distribution.
// Using a value less than one disables this behaviour. If the current value of
// N is already higher, then it will be set to `maxN` immediately. A value too
// low may cause instability, while a value too high may reduce adaptability.
//
// NOTE: A recommended starting value is 500, if your application can tolerate
// it, and probably no less than 100 otherwise. This recommendation could change
// in future versions.
func (s *Stats) SetMaxN(maxN float64) {
if maxN < 1 {
maxN = 0
} else {
maxN = math.Round(maxN)
}
s.maxN = maxN
if s.maxN >= 1 && s.n > s.maxN {
s.n = s.maxN
}
}
// Mean returns the Arithmetic Mean of the pushed values.
func (s *Stats) Mean() float64 { return s.newM }
// StdDev returns the (Population) Standard Deviation of the pushed values. If
// less than 2 values were pushed, then NaN is returned.
func (s *Stats) StdDev() float64 {
if s.actualN > 1 {
return math.Sqrt(s.newS / s.actualN)
}
return math.NaN()
}