vitess.io/vitess@v0.16.2/go/mathstats/beta.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 mathstats 6 7 import "math" 8 9 func lgamma(x float64) float64 { 10 y, _ := math.Lgamma(x) 11 return y 12 } 13 14 // mathBetaInc returns the value of the regularized incomplete beta 15 // function Iₓ(a, b). 16 // 17 // This is not to be confused with the "incomplete beta function", 18 // which can be computed as BetaInc(x, a, b)*Beta(a, b). 19 // 20 // If x < 0 or x > 1, returns NaN. 21 func mathBetaInc(x, a, b float64) float64 { 22 // Based on Numerical Recipes in C, section 6.4. This uses the 23 // continued fraction definition of I: 24 // 25 // (xᵃ*(1-x)ᵇ)/(a*B(a,b)) * (1/(1+(d₁/(1+(d₂/(1+...)))))) 26 // 27 // where B(a,b) is the beta function and 28 // 29 // d_{2m+1} = -(a+m)(a+b+m)x/((a+2m)(a+2m+1)) 30 // d_{2m} = m(b-m)x/((a+2m-1)(a+2m)) 31 if x < 0 || x > 1 { 32 return math.NaN() 33 } 34 bt := 0.0 35 if 0 < x && x < 1 { 36 // Compute the coefficient before the continued 37 // fraction. 38 bt = math.Exp(lgamma(a+b) - lgamma(a) - lgamma(b) + 39 a*math.Log(x) + b*math.Log(1-x)) 40 } 41 if x < (a+1)/(a+b+2) { 42 // Compute continued fraction directly. 43 return bt * betacf(x, a, b) / a 44 } else { 45 // Compute continued fraction after symmetry transform. 46 return 1 - bt*betacf(1-x, b, a)/b 47 } 48 } 49 50 // betacf is the continued fraction component of the regularized 51 // incomplete beta function Iₓ(a, b). 52 func betacf(x, a, b float64) float64 { 53 const maxIterations = 200 54 const epsilon = 3e-14 55 56 raiseZero := func(z float64) float64 { 57 if math.Abs(z) < math.SmallestNonzeroFloat64 { 58 return math.SmallestNonzeroFloat64 59 } 60 return z 61 } 62 63 c := 1.0 64 d := 1 / raiseZero(1-(a+b)*x/(a+1)) 65 h := d 66 for m := 1; m <= maxIterations; m++ { 67 mf := float64(m) 68 69 // Even step of the recurrence. 70 numer := mf * (b - mf) * x / ((a + 2*mf - 1) * (a + 2*mf)) 71 d = 1 / raiseZero(1+numer*d) 72 c = raiseZero(1 + numer/c) 73 h *= d * c 74 75 // Odd step of the recurrence. 76 numer = -(a + mf) * (a + b + mf) * x / ((a + 2*mf) * (a + 2*mf + 1)) 77 d = 1 / raiseZero(1+numer*d) 78 c = raiseZero(1 + numer/c) 79 hfac := d * c 80 h *= hfac 81 82 if math.Abs(hfac-1) < epsilon { 83 return h 84 } 85 } 86 panic("betainc: a or b too big; failed to converge") 87 }