github.com/jgbaldwinbrown/perf@v0.1.1/pkg/stats/alg.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package stats 6 7 // Miscellaneous helper algorithms 8 9 import ( 10 "fmt" 11 ) 12 13 func maxint(a, b int) int { 14 if a > b { 15 return a 16 } 17 return b 18 } 19 20 func minint(a, b int) int { 21 if a < b { 22 return a 23 } 24 return b 25 } 26 27 func sumint(xs []int) int { 28 sum := 0 29 for _, x := range xs { 30 sum += x 31 } 32 return sum 33 } 34 35 // bisect returns an x in [low, high] such that |f(x)| <= tolerance 36 // using the bisection method. 37 // 38 // f(low) and f(high) must have opposite signs. 39 // 40 // If f does not have a root in this interval (e.g., it is 41 // discontiguous), this returns the X of the apparent discontinuity 42 // and false. 43 func bisect(f func(float64) float64, low, high, tolerance float64) (float64, bool) { 44 flow, fhigh := f(low), f(high) 45 if -tolerance <= flow && flow <= tolerance { 46 return low, true 47 } 48 if -tolerance <= fhigh && fhigh <= tolerance { 49 return high, true 50 } 51 if mathSign(flow) == mathSign(fhigh) { 52 panic(fmt.Sprintf("root of f is not bracketed by [low, high]; f(%g)=%g f(%g)=%g", low, flow, high, fhigh)) 53 } 54 for { 55 mid := (high + low) / 2 56 fmid := f(mid) 57 if -tolerance <= fmid && fmid <= tolerance { 58 return mid, true 59 } 60 if mid == high || mid == low { 61 return mid, false 62 } 63 if mathSign(fmid) == mathSign(flow) { 64 low = mid 65 flow = fmid 66 } else { 67 high = mid 68 fhigh = fmid 69 } 70 } 71 } 72 73 // bisectBool implements the bisection method on a boolean function. 74 // It returns x1, x2 ∈ [low, high], x1 < x2 such that f(x1) != f(x2) 75 // and x2 - x1 <= xtol. 76 // 77 // If f(low) == f(high), it panics. 78 func bisectBool(f func(float64) bool, low, high, xtol float64) (x1, x2 float64) { 79 flow, fhigh := f(low), f(high) 80 if flow == fhigh { 81 panic(fmt.Sprintf("root of f is not bracketed by [low, high]; f(%g)=%v f(%g)=%v", low, flow, high, fhigh)) 82 } 83 for { 84 if high-low <= xtol { 85 return low, high 86 } 87 mid := (high + low) / 2 88 if mid == high || mid == low { 89 return low, high 90 } 91 fmid := f(mid) 92 if fmid == flow { 93 low = mid 94 flow = fmid 95 } else { 96 high = mid 97 fhigh = fmid 98 } 99 } 100 } 101 102 // series returns the sum of the series f(0), f(1), ... 103 // 104 // This implementation is fast, but subject to round-off error. 105 func series(f func(float64) float64) float64 { 106 y, yp := 0.0, 1.0 107 for n := 0.0; y != yp; n++ { 108 yp = y 109 y += f(n) 110 } 111 return y 112 }