github.com/blend/go-sdk@v1.20220411.3/mathutil/percentile.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package mathutil
     9  
    10  import (
    11  	"math"
    12  	"time"
    13  )
    14  
    15  // Percentile finds the relative standing in a slice of floats.
    16  // `percent` should be given on the interval [0,100.0).
    17  func Percentile(input []float64, percent float64) float64 {
    18  	if len(input) == 0 {
    19  		return 0
    20  	}
    21  
    22  	return PercentileSorted(CopySort(input), percent)
    23  }
    24  
    25  // PercentileSorted finds the relative standing in a sorted slice of floats.
    26  // `percent` should be given on the interval [0,100.0).
    27  func PercentileSorted(sortedInput []float64, percent float64) float64 {
    28  	index := (percent / 100.0) * float64(len(sortedInput))
    29  	percentile := float64(0)
    30  	i := int(math.RoundToEven(index))
    31  	if index == float64(int64(index)) {
    32  		percentile = (sortedInput[i-1] + sortedInput[i]) / 2.0
    33  	} else {
    34  		percentile = sortedInput[i-1]
    35  	}
    36  
    37  	return percentile
    38  }
    39  
    40  // PercentileOfDuration finds the relative standing in a slice of durations
    41  func PercentileOfDuration(input []time.Duration, percentile float64) time.Duration {
    42  	if len(input) == 0 {
    43  		return 0
    44  	}
    45  	return PercentileSortedDurations(CopySortDurations(input), percentile)
    46  }
    47  
    48  // PercentileSortedDurations finds the relative standing in a sorted slice of durations
    49  func PercentileSortedDurations(sortedInput []time.Duration, percentile float64) time.Duration {
    50  	index := (percentile / 100.0) * float64(len(sortedInput))
    51  	if index == float64(int64(index)) {
    52  		i := int(RoundPlaces(index, 0))
    53  
    54  		if i < 1 {
    55  			return time.Duration(0)
    56  		}
    57  
    58  		return MeanDurations([]time.Duration{sortedInput[i-1], sortedInput[i]})
    59  	}
    60  
    61  	i := int(RoundPlaces(index, 0))
    62  	if i < 1 {
    63  		return time.Duration(0)
    64  	}
    65  
    66  	return sortedInput[i-1]
    67  }