Add base Percentile interface and tests
This commit is contained in:
parent
8d8c1fba62
commit
2f4d0b0f9a
2 changed files with 75 additions and 0 deletions
45
stats/percentile.go
Normal file
45
stats/percentile.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package stats
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
type Percentile struct {
|
||||
percentile float64
|
||||
values sort.Float64Slice
|
||||
offset int
|
||||
}
|
||||
|
||||
func NewPercentile(percentile float64, sampleWindow int) *Percentile {
|
||||
return &Percentile{
|
||||
percentile: percentile,
|
||||
values: make([]float64, 0, sampleWindow),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Percentile) AddSample(sample float64) {
|
||||
p.values = append(p.values, sample)
|
||||
sort.Sort(p.values)
|
||||
}
|
||||
|
||||
func (p *Percentile) Value() float64 {
|
||||
if len(p.values) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return p.values[round(p.index())]
|
||||
}
|
||||
|
||||
func (p *Percentile) index() float64 {
|
||||
return float64(len(p.values)) * p.percentile - float64(p.offset)
|
||||
}
|
||||
|
||||
func round(value float64) int64 {
|
||||
if value < 0.0 {
|
||||
value -= 0.5
|
||||
} else {
|
||||
value += 0.5
|
||||
}
|
||||
|
||||
return int64(value)
|
||||
}
|
30
stats/percentile_test.go
Normal file
30
stats/percentile_test.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package stats
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func TestPercentiles(t *testing.T) {
|
||||
testInRange(t, 1, 0.5)
|
||||
testInRange(t, 1, 0.9)
|
||||
testInRange(t, 1, 0.95)
|
||||
testInRange(t, 10000, 0.5)
|
||||
testInRange(t, 10000, 0.9)
|
||||
testInRange(t, 10000, 0.95)
|
||||
}
|
||||
|
||||
func testInRange(t *testing.T, max, percentile float64) {
|
||||
p := NewPercentile(percentile, 10)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
p.AddSample(rand.Float64() * max)
|
||||
}
|
||||
|
||||
got := p.Value()
|
||||
expected := percentile * max
|
||||
|
||||
if got < expected * (1 - 0.02) || got > expected * (1 + 0.02) {
|
||||
t.Errorf("Percentile out of range\n actual: %f\nexpected: %f", got, expected)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue