v0.0.482 mathext.Percentile
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 3m46s

This commit is contained in:
2024-07-12 16:33:42 +02:00
parent abc8af525a
commit 6ded615723
6 changed files with 307 additions and 7 deletions

View File

@@ -1,6 +1,9 @@
package mathext
import "gogs.mikescher.com/BlackForestBytes/goext/langext"
import (
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
)
func Sum[T langext.NumberConstraint](v []T) T {
total := T(0)
@@ -41,3 +44,53 @@ func ArrMax[T langext.OrderedConstraint](v []T) T {
}
return r
}
func MustPercentile[T langext.NumberConstraint](rawdata []T, percentile float64) T {
v, err := Percentile(rawdata, percentile)
if err != nil {
panic(err)
}
return v
}
func Percentile[T langext.NumberConstraint](rawdata []T, percentile float64) (T, error) {
v, err := FloatPercentile(rawdata, percentile)
if err != nil {
return T(0), err
}
return T(v), nil
}
func FloatPercentile[T langext.NumberConstraint](rawdata []T, percentile float64) (float64, error) {
if len(rawdata) == 0 {
return 0, exerr.New(exerr.TypeAssert, "no data to calculate percentile").Any("percentile", percentile).Build()
}
if percentile < 0 || percentile > 100 {
return 0, exerr.New(exerr.TypeAssert, "percentile out of range").Any("percentile", percentile).Build()
}
data := langext.ArrCopy(rawdata)
langext.Sort(data)
idxFloat := float64(len(data)-1) * (percentile / float64(100))
idxInt := int(idxFloat)
// exact match on index
if idxFloat == float64(idxInt) {
return float64(data[idxInt]), nil
}
// linear interpolation
v1 := data[idxInt]
v2 := data[idxInt+1]
weight := idxFloat - float64(idxInt)
valFloat := (float64(v1) * (1 - weight)) + (float64(v2) * weight)
return valFloat, nil
}