commit
e7e174530e
@ -0,0 +1,56 @@ |
||||
package ostat |
||||
|
||||
import ( |
||||
"errors" |
||||
"math" |
||||
) |
||||
|
||||
// from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
|
||||
|
||||
type OnlineStat struct { |
||||
n int64 |
||||
mean float64 |
||||
m2 float64 |
||||
Max float64 |
||||
Min float64 |
||||
} |
||||
|
||||
func NewOnlineStat() *OnlineStat { |
||||
return &OnlineStat{ |
||||
Min: math.Inf(1), |
||||
Max: math.Inf(-1), |
||||
} |
||||
} |
||||
|
||||
func (os *OnlineStat) Push(v float64) { |
||||
os.n += 1 |
||||
if v < os.Min { |
||||
os.Min = v |
||||
} |
||||
if v > os.Max { |
||||
os.Max = v |
||||
} |
||||
|
||||
delta := v - os.mean |
||||
os.mean = os.mean + delta/float64(os.n) |
||||
os.m2 = os.m2 + delta*(v-os.mean) |
||||
} |
||||
|
||||
func (os *OnlineStat) Mean() (float64, error) { |
||||
if os.n == 0 { |
||||
return 0.0, errors.New("no data") |
||||
} |
||||
return os.mean, nil |
||||
} |
||||
|
||||
func (os *OnlineStat) Variance() (float64, error) { |
||||
if os.n == 0 { |
||||
return 0.0, errors.New("no data") |
||||
} |
||||
return os.m2 / float64(os.n-1), nil |
||||
} |
||||
|
||||
func (os *OnlineStat) StdDev() (float64, error) { |
||||
variance, err := os.Variance() |
||||
return math.Sqrt(variance), err |
||||
} |
@ -0,0 +1,45 @@ |
||||
package ostat |
||||
|
||||
import ( |
||||
"math" |
||||
"testing" |
||||
) |
||||
|
||||
func TestInsert(t *testing.T) { |
||||
os := NewOnlineStat() |
||||
v := []float64{4, 7, 13, 16} |
||||
for _, i := range v { |
||||
os.Push(i) |
||||
} |
||||
if os.Min != 4 { |
||||
t.Errorf("incorrectly calculated min") |
||||
} |
||||
if os.Max != 16 { |
||||
t.Errorf("incorrectly calculated max") |
||||
} |
||||
if m, _ := os.Mean(); m != 10.0 { |
||||
t.Errorf("incorrect mean") |
||||
} |
||||
if variance, _ := os.Variance(); variance != 30.0 { |
||||
t.Errorf("incorrect variance: %f", variance) |
||||
} |
||||
if stdev, _ := os.StdDev(); stdev != math.Sqrt(30.0) { |
||||
t.Errorf("incorrect stdev: %f", stdev) |
||||
} |
||||
} |
||||
|
||||
func TestEmpty(t *testing.T) { |
||||
os := NewOnlineStat() |
||||
_, err := os.Mean() |
||||
if err == nil { |
||||
t.Errorf("failure to notify the running stat was empty") |
||||
} |
||||
_, err = os.Variance() |
||||
if err == nil { |
||||
t.Errorf("failure to notify the running stat was empty") |
||||
} |
||||
_, err = os.StdDev() |
||||
if err == nil { |
||||
t.Errorf("failure to notify the running stat was empty") |
||||
} |
||||
} |
Loading…
Reference in new issue