Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 

71 Zeilen
2.0 KiB

  1. // Copyright 2017 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package distribution
  15. import (
  16. "log"
  17. "math"
  18. "sort"
  19. "sync/atomic"
  20. )
  21. // D is a distribution. Methods of D can be called concurrently by multiple
  22. // goroutines.
  23. type D struct {
  24. buckets []uint64
  25. }
  26. // New creates a new distribution capable of holding values from 0 to n-1.
  27. func New(n int) *D {
  28. return &D{
  29. buckets: make([]uint64, n),
  30. }
  31. }
  32. // Record records value v to the distribution.
  33. // To help with distributions with long tails, if v is larger than the maximum value,
  34. // Record records the maximum value instead.
  35. // If v is negative, Record panics.
  36. func (d *D) Record(v int) {
  37. if v < 0 {
  38. log.Panicf("Record: value out of range: %d", v)
  39. } else if v >= len(d.buckets) {
  40. v = len(d.buckets) - 1
  41. }
  42. atomic.AddUint64(&d.buckets[v], 1)
  43. }
  44. // Percentile computes the p-th percentile of the distribution where
  45. // p is between 0 and 1.
  46. func (d *D) Percentile(p float64) int {
  47. // NOTE: This implementation uses the nearest-rank method.
  48. // https://en.wikipedia.org/wiki/Percentile#The_nearest-rank_method
  49. if p < 0 || p > 1 {
  50. log.Panicf("Percentile: percentile out of range: %f", p)
  51. }
  52. bucketSums := make([]uint64, len(d.buckets))
  53. var sum uint64
  54. for i := range bucketSums {
  55. sum += atomic.LoadUint64(&d.buckets[i])
  56. bucketSums[i] = sum
  57. }
  58. total := bucketSums[len(bucketSums)-1]
  59. target := uint64(math.Ceil(float64(total) * p))
  60. return sort.Search(len(bucketSums), func(i int) bool { return bucketSums[i] >= target })
  61. }