1use crate::common::f_fmla;
30use crate::gamma::lnbetaf::lnbetaf_core;
31use crate::{f_exp, f_log, f_log1p, f_pow, f_powf};
32
33pub fn f_betainc_regf(a: f32, b: f32, x: f32) -> f32 {
35 let aa = a.to_bits();
36 let ab = b.to_bits();
37 let ax = x.to_bits();
38
39 if aa >= 0xffu32 << 23
40 || aa == 0
41 || ab >= 0xffu32 << 23
42 || ab == 0
43 || ax == 0
44 || ax >= 0x3f800000
45 {
46 if (aa >> 31) != 0 || (ab >> 31) != 0 || (ax >> 31) != 0 {
47 return f32::NAN;
49 }
50 if ax >= 0x3f800000 {
51 if ax == 0x3f800000 {
53 return 1.;
55 }
56 return f32::NAN;
57 }
58 if aa.wrapping_shl(1) == 0 {
59 return 1.0;
61 }
62 if ab.wrapping_shl(1) == 0 {
63 return 0.;
65 }
66 if ax.wrapping_shl(1) == 0 {
67 return 0.;
69 }
70 if a.is_infinite() {
71 return 0.;
73 }
74 if b.is_infinite() {
75 return 1.;
77 }
78 return a + f32::NAN; }
80
81 if aa == 0x3f800000 {
82 return (1. - f_pow(1. - x as f64, b as f64)) as f32;
84 }
85
86 if ab == 0x3f800000 {
87 return f_powf(x, a);
89 }
90
91 let mut return_inverse = false;
94 let mut dx = x as f64;
95 let mut a = a;
96 let mut b = b;
97 if x > (a + 1.0) / (a + b + 2.0) {
98 std::mem::swap(&mut a, &mut b);
99 dx = 1.0 - dx;
100 return_inverse = true;
101 }
102 let da = a as f64;
104 let db = b as f64;
105 let w0 = f_fmla(f_log(dx), da, f_fmla(f_log1p(-dx), db, -lnbetaf_core(a, b)));
106 let front = f_exp(w0) / da;
107
108 let mut f = 1.0;
110 let mut c = 1.0;
111 let mut d = 0.0;
112
113 const TINY: f64 = 1.0e-30;
114 const STOP: f64 = 1.0e-8;
115
116 for i in 0..200 {
117 let m = i / 2;
118 let numerator: f64 = if i == 0 {
119 1.0 } else if i % 2 == 0 {
121 let m = m as f64;
122 let c0 = f_fmla(2.0, m, da);
123 (m * (db - m) * dx) / ((c0 - 1.0) * c0) } else {
125 let m = m as f64;
126 let c0 = f_fmla(2.0, m, da);
127 -((da + m) * (da + db + m) * dx) / (c0 * (c0 + 1.)) };
129
130 d = f_fmla(numerator, d, 1.0);
132 if d.abs() < TINY {
133 d = TINY;
134 }
135 d = 1.0 / d;
136
137 c = 1.0 + numerator / c;
138 if c.abs() < TINY {
139 c = TINY;
140 }
141
142 let cd = c * d;
143 f *= cd;
144
145 if (1.0 - cd).abs() < STOP {
147 return if return_inverse {
148 f_fmla(-front, f - 1.0, 1.) as f32
149 } else {
150 (front * (f - 1.0)) as f32
151 };
152 }
153 }
154
155 if return_inverse {
156 f_fmla(-front, f - 1.0, 1.) as f32
157 } else {
158 (front * (f - 1.0)) as f32
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_betaincf() {
168 assert_eq!(f_betainc_regf(0.5, 2.5, 0.5), 0.9244131815783875);
169 assert_eq!(f_betainc_regf(2.5, 1.0, 0.5), 0.1767766952966368811);
170 assert_eq!(f_betainc_regf(0.5, 0.5, 0.5), 0.5);
171 assert_eq!(f_betainc_regf(54221., 23124., 0.64534), 0.0);
172 assert_eq!(f_betainc_regf(5., 1.4324, 0.1312), 8.872578e-5);
173 assert_eq!(f_betainc_regf(7., 42., 0.4324), 0.99999547);
174 assert_eq!(f_betainc_regf(0.5, 0., 1.), 1.);
175 assert_eq!(f_betainc_regf(5., 2., 1.), 1.);
176 assert_eq!(f_betainc_regf(5., 2., 0.), 0.);
177 assert_eq!(f_betainc_regf(5., 2., 0.5), 0.109375);
178 assert!(f_betainc_regf(5., 2., -1.).is_nan());
179 assert!(f_betainc_regf(5., 2., 1.1).is_nan());
180 assert!(f_betainc_regf(5., 2., f32::INFINITY).is_nan());
181 assert!(f_betainc_regf(5., 2., f32::NEG_INFINITY).is_nan());
182 assert!(f_betainc_regf(5., 2., f32::NAN).is_nan());
183 assert!(f_betainc_regf(-5., 2., 0.432).is_nan());
184 assert!(f_betainc_regf(5., -2., 0.432).is_nan());
185 assert!(f_betainc_regf(5., 2., -0.432).is_nan());
186 }
187}