1use crate::{ln_gamma, EPS, FPMIN, W, Y};
9const SWITCH: usize = 3000;
10
11pub fn beta(z: f64, w: f64) -> f64 {
30 (ln_gamma(z) + ln_gamma(w) - ln_gamma(z + w)).exp()
31}
32
33pub fn betai(a: f64, b: f64, x: f64) -> f64 {
58 assert!(a > 0f64 && b > 0f64, "Bad a or b in routine betai");
59 assert!((0f64..=1f64).contains(&x), "Bad x in routine betai");
60 if x == 0f64 || x == 1f64 {
61 return x;
62 }
63 let switch = SWITCH as f64;
64 if a > switch && b > switch {
65 return betaiapprox(a, b, x);
66 }
67 let bt = (ln_gamma(a + b) - ln_gamma(a) - ln_gamma(b) + a * x.ln() + b * (1f64 - x).ln()).exp();
68 if x < (a + 1f64) / (a + b * 2f64) {
69 bt * betacf(a, b, x) / a
70 } else {
71 1f64 - bt * betacf(b, a, 1f64 - x) / b
72 }
73}
74
75fn betacf(a: f64, b: f64, x: f64) -> f64 {
77 let qab = a + b;
78 let qap = a + 1f64;
79 let qam = a - 1f64;
80 let mut c = 1f64;
81 let mut d = 1f64 - qab * x / qap;
82 if d.abs() < FPMIN {
83 d = FPMIN;
84 }
85 d = 1f64 / d;
86 let mut h = d;
87 for m in 1..10000 {
88 let m = m as f64;
89 let m2 = 2f64 * m;
90 let mut aa = m * (b - m) * x / ((qam + m2) * (a + m2));
91 d = 1f64 + aa * d;
92 if d.abs() < FPMIN {
93 d = FPMIN;
94 }
95 c = 1f64 + aa / c;
96 if c.abs() < FPMIN {
97 c = FPMIN;
98 }
99 d = 1f64 / d;
100 h *= d * c;
101 aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
102 d = 1f64 + aa * d;
103 if d.abs() < FPMIN {
104 d = FPMIN;
105 }
106 c = 1f64 + aa / c;
107 if c.abs() < FPMIN {
108 c = FPMIN;
109 }
110 d = 1f64 / d;
111 let del = d * c;
112 h *= del;
113 if (del - 1f64).abs() <= EPS {
114 break;
115 }
116 }
117 h
118}
119
120fn betaiapprox(a: f64, b: f64, x: f64) -> f64 {
122 let a1 = a - 1f64;
123 let b1 = b - 1f64;
124 let mu = a / (a + b);
125 let lnmu = mu.ln();
126 let lnmuc = (1f64 - mu).ln();
127 let mut t = (a * b / ((a + b).powi(2) * (a + b + 1f64))).sqrt();
128 let xu = if x > a / (a + b) {
129 if x >= 1f64 {
130 return 1f64;
131 }
132 1f64.min((mu + 10f64 * t).max(x + 5f64 * t))
133 } else {
134 if x <= 0f64 {
135 return 0f64;
136 }
137 0f64.max((mu - 10f64 * t).min(x - 5f64 * t))
138 };
139 let mut sum = 0f64;
140 for j in 0..18 {
141 t = x + (xu - x) * Y[j];
142 sum += W[j] * (a1 * (t.ln() - lnmu) + b1 * (1f64 - t).ln() - lnmuc).exp();
143 }
144 let ans = sum
145 * (xu - x)
146 * (a1 * lnmu - ln_gamma(a) + b1 * lnmuc - ln_gamma(b) + ln_gamma(a + b)).exp();
147 if ans > 0f64 {
148 1f64 - ans
149 } else {
150 -ans
151 }
152}
153
154pub fn invbetai(p: f64, a: f64, b: f64) -> f64 {
173 let a1 = a - 1f64;
174 let b1 = b - 1f64;
175 let mut t: f64;
176 let mut x: f64;
177 let mut u: f64;
178 if p <= 0f64 {
179 return 0f64;
180 } else if p >= 1f64 {
181 return 1f64;
182 } else if a >= 1f64 && b >= 1f64 {
183 let pp = if p < 0.5 { p } else { 1f64 - p };
184 t = (-2f64 * pp.ln()).sqrt();
185 x = (2.30753 + t * 0.27061) / (1f64 + t * (0.99229 + t * 0.04481)) - t;
186 if p < 0.5 {
187 x = -x;
188 }
189 let al = (x.powi(2) - 3f64) / 6f64;
190 let h = 2f64 / (1f64 / (2f64 * a - 1f64) + 1f64 / (2f64 * b - 1f64));
191 let w = (x * (al + h).sqrt() / h)
192 - (1f64 / (2f64 * b - 1f64) - 1f64 / (2f64 * a - 1f64))
193 * (al + 5f64 / 6f64 - 2f64 / (3f64 * h));
194 x = a / (a + b * (2f64 * w).exp());
195 } else {
196 let lna = (a / (a + b)).ln();
197 let lnb = (b / (a + b)).ln();
198 t = (a * lna).exp() / a;
199 u = (b * lnb).exp() / b;
200 let w = t + u;
201 x = if p < t / w {
202 (a * w * p).powf(1f64 / a)
203 } else {
204 1f64 - (b * w * (1f64 - p)).powf(1f64 / b)
205 };
206 }
207 let afac = -ln_gamma(a) - ln_gamma(b) + ln_gamma(a + b);
208 for j in 0..10 {
209 if x == 0f64 || x == 1f64 {
210 return x;
211 }
212 let err = betai(a, b, x) - p;
213 t = (a1 * x.ln() + b1 * (1f64 - x).ln() + afac).exp();
214 u = err / t;
215 t = u / (1f64 - 0.5 * 1f64.min(u * (a1 / x - b1 / (1f64 - x))));
216 x -= t;
217 if x <= 0f64 {
218 x = 0.5 * (x + t);
219 }
220 if x >= 1f64 {
221 x = 0.5 * (x + t + 1f64);
222 }
223 if t.abs() < EPS * x && j > 0 {
224 break;
225 }
226 }
227 x
228}