...

Source file src/github.com/go-kit/kit/metrics/teststat/populate.go

Documentation: github.com/go-kit/kit/metrics/teststat

     1  package teststat
     2  
     3  import (
     4  	"math"
     5  	"math/rand"
     6  
     7  	"github.com/go-kit/kit/metrics"
     8  )
     9  
    10  // PopulateNormalHistogram makes a series of normal random observations into the
    11  // histogram. The number of observations is determined by Count. The randomness
    12  // is determined by Mean, Stdev, and the seed parameter.
    13  //
    14  // This is a low-level function, exported only for metrics that don't perform
    15  // dynamic quantile computation, like a Prometheus Histogram (c.f. Summary). In
    16  // most cases, you don't need to use this function, and can use TestHistogram
    17  // instead.
    18  func PopulateNormalHistogram(h metrics.Histogram, seed int) {
    19  	r := rand.New(rand.NewSource(int64(seed)))
    20  	for i := 0; i < Count; i++ {
    21  		sample := r.NormFloat64()*float64(Stdev) + float64(Mean)
    22  		if sample < 0 {
    23  			sample = 0
    24  		}
    25  		h.Observe(sample)
    26  	}
    27  }
    28  
    29  func normalQuantiles() (p50, p90, p95, p99 float64) {
    30  	return nvq(50), nvq(90), nvq(95), nvq(99)
    31  }
    32  
    33  func nvq(quantile int) float64 {
    34  	// https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function
    35  	return float64(Mean) + float64(Stdev)*math.Sqrt2*erfinv(2*(float64(quantile)/100)-1)
    36  }
    37  
    38  func erfinv(y float64) float64 {
    39  	// https://stackoverflow.com/questions/5971830/need-code-for-inverse-error-function
    40  	if y < -1.0 || y > 1.0 {
    41  		panic("invalid input")
    42  	}
    43  
    44  	var (
    45  		a = [4]float64{0.886226899, -1.645349621, 0.914624893, -0.140543331}
    46  		b = [4]float64{-2.118377725, 1.442710462, -0.329097515, 0.012229801}
    47  		c = [4]float64{-1.970840454, -1.624906493, 3.429567803, 1.641345311}
    48  		d = [2]float64{3.543889200, 1.637067800}
    49  	)
    50  
    51  	const y0 = 0.7
    52  	var x, z float64
    53  
    54  	if math.Abs(y) == 1.0 {
    55  		x = -y * math.Log(0.0)
    56  	} else if y < -y0 {
    57  		z = math.Sqrt(-math.Log((1.0 + y) / 2.0))
    58  		x = -(((c[3]*z+c[2])*z+c[1])*z + c[0]) / ((d[1]*z+d[0])*z + 1.0)
    59  	} else {
    60  		if y < y0 {
    61  			z = y * y
    62  			x = y * (((a[3]*z+a[2])*z+a[1])*z + a[0]) / ((((b[3]*z+b[3])*z+b[1])*z+b[0])*z + 1.0)
    63  		} else {
    64  			z = math.Sqrt(-math.Log((1.0 - y) / 2.0))
    65  			x = (((c[3]*z+c[2])*z+c[1])*z + c[0]) / ((d[1]*z+d[0])*z + 1.0)
    66  		}
    67  		x -= (math.Erf(x) - y) / (2.0 / math.SqrtPi * math.Exp(-x*x))
    68  		x -= (math.Erf(x) - y) / (2.0 / math.SqrtPi * math.Exp(-x*x))
    69  	}
    70  
    71  	return x
    72  }
    73  

View as plain text