diff --git a/src/math/stats.go b/src/math/stats.go index a8b1136892f..ee1d160639a 100644 --- a/src/math/stats.go +++ b/src/math/stats.go @@ -12,8 +12,7 @@ import ( // Mean returns the mean (average) of a slice of float64 numbers. // // Special cases are: -// -// Mean([]float64{}) = 0 +// Mean([]float64{}) = 0 func Mean(numbers []float64) float64 { if len(numbers) == 0 { return 0 @@ -30,29 +29,30 @@ func Mean(numbers []float64) float64 { // Median returns the median of a slice of float64 numbers. // // Special cases are: -// -// Median([]float64{}) = 0 +// Median([]float64{}) = 0 func Median(numbers []float64) float64 { if len(numbers) == 0 { return 0 } + // Create a sorted copy of the input slice sorted := make([]float64, len(numbers)) copy(sorted, numbers) sort.Float64s(sorted) n := len(sorted) if n%2 == 0 { + // If even, return the average of the two middle numbers return (sorted[n/2-1] + sorted[n/2]) / 2 } + // If odd, return the middle number return sorted[n/2] } // Mode returns the mode(s) of a slice of float64 numbers. // // Special cases are: -// -// Mode([]float64{}) = nil +// Mode([]float64{}) = nil func Mode(numbers []float64) []float64 { if len(numbers) == 0 { return nil @@ -83,8 +83,7 @@ func Mode(numbers []float64) []float64 { // Variance returns the variance of a slice of float64 numbers. // // Special cases are: -// -// Variance([]float64{}) = 0 +// Variance([]float64{}) = 0 func Variance(numbers []float64) float64 { if len(numbers) == 0 { return 0 @@ -103,8 +102,34 @@ func Variance(numbers []float64) float64 { // StdDev returns the standard deviation of a slice of float64 numbers. // // Special cases are: -// -// StdDev([]float64{}) = 0 +// StdDev([]float64{}) = 0 func StdDev(numbers []float64) float64 { return math.Sqrt(Variance(numbers)) -} \ No newline at end of file +} + +// Percentile returns the p-th percentile of a slice of float64 numbers. +// The percentile is the value below which a given percentage of observations fall. +// +// Special cases are: +// Percentile([]float64{}, p) = 0 for any p +func Percentile(numbers []float64, p float64) float64 { + if len(numbers) == 0 || p < 0 || p > 100 { + return 0 + } + + // Sort the slice + sorted := make([]float64, len(numbers)) + copy(sorted, numbers) + sort.Float64s(sorted) + + index := (p / 100) * float64(len(sorted)-1) + i := int(index) + + // Handle the case for interpolation between two values if not an integer + if index == float64(i) { + return sorted[i] + } + + // Linear interpolation + return sorted[i]*(float64(i+1)-index) + sorted[i+1]*(index-float64(i)) +}