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  }