diff options
Diffstat (limited to 'utilities/math.go')
| -rw-r--r-- | utilities/math.go | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/utilities/math.go b/utilities/math.go new file mode 100644 index 0000000..1ecca61 --- /dev/null +++ b/utilities/math.go @@ -0,0 +1,144 @@ +/* + * This file is part of Go Responsiveness. + * + * Go Responsiveness is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * either version 2 of the License, or (at your option) any later version. + * Go Responsiveness is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with Go Responsiveness. If not, see <https://www.gnu.org/licenses/>. + */ + +package utilities + +import ( + "math" + "sort" + + "golang.org/x/exp/constraints" + "golang.org/x/exp/slices" +) + +type Number interface { + constraints.Float | constraints.Integer +} + +func CalculateAverage[T Number](elements []T) float64 { + total := T(0) + for i := 0; i < len(elements); i++ { + total += elements[i] + } + return float64(total) / float64(len(elements)) +} + +func CalculatePercentile[T Number]( + elements []T, + p int, +) (result T) { + result = T(0) + if p < 0 || p > 100 { + return + } + + sort.Slice(elements, func(l int, r int) bool { return elements[l] < elements[r] }) + pindex := int64((float64(p) / float64(100)) * float64(len(elements))) + result = elements[pindex] + return +} + +func Max(x, y uint64) uint64 { + if x > y { + return x + } + return y +} + +func SignedPercentDifference[T constraints.Float | constraints.Integer]( + current T, + previous T, +) (difference float64) { + fCurrent := float64(current) + fPrevious := float64(previous) + return ((fCurrent - fPrevious) / fPrevious) * 100.0 +} + +func AbsPercentDifference( + current float64, + previous float64, +) (difference float64) { + return (math.Abs(current-previous) / (float64(current+previous) / 2.0)) * float64( + 100, + ) +} + +func CalculateStandardDeviation[T constraints.Float | constraints.Integer](elements []T) float64 { + // From https://www.mathsisfun.com/data/standard-deviation-calculator.html + // Yes, for real! + + // Calculate the average of the numbers ... + average := CalculateAverage(elements) + + // Calculate the square of each of the elements' differences from the mean. + differences_squared := make([]float64, len(elements)) + for index, value := range elements { + differences_squared[index] = math.Pow(float64(value-T(average)), 2) + } + + // The variance is the average of the squared differences. + // So, we need to ... + + // Accumulate all those squared differences. + sds := float64(0) + for _, dss := range differences_squared { + sds += dss + } + + // And then divide that total by the number of elements + variance := sds / float64(len(elements)) + + // Finally, the standard deviation is the square root + // of the variance. + sd := float64(math.Sqrt(variance)) + // sd := T(variance) + + return sd +} + +func AllSequentialIncreasesLessThan[T Number](elements []T, limit float64) (bool, float64) { + if len(elements) < 2 { + return false, 0.0 + } + + maximumSequentialIncrease := float64(0) + for i := 1; i < len(elements); i++ { + current := elements[i] + previous := elements[i-1] + percentChange := SignedPercentDifference(current, previous) + if percentChange > limit { + return false, percentChange + } + if percentChange > float64(maximumSequentialIncrease) { + maximumSequentialIncrease = percentChange + } + } + return true, maximumSequentialIncrease +} + +// elements must already be sorted! +func TrimBy[T Number](elements []T, trim int) []T { + numberToKeep := int(float32(len(elements)) * (float32(trim) / 100.0)) + + return elements[:numberToKeep] +} + +func TrimmedMean[T Number](elements []T, trim int) (float64, []T) { + sortedElements := make([]T, len(elements)) + copy(sortedElements, elements) + slices.Sort(sortedElements) + + trimmedElements := TrimBy(sortedElements, trim) + return CalculateAverage(trimmedElements), trimmedElements +} |
