1use crate::common::f_fmla;
30use crate::exponents::core_expdf;
31use crate::gamma::lgamma_rf::lgamma_coref;
32use crate::logs::fast_logf;
33
34pub fn f_gamma_pf(a: f32, x: f32) -> f32 {
36 let aa = a.to_bits();
37 let ax = x.to_bits();
38
39 if aa >= 0xffu32 << 23 || aa == 0 || ax >= 0xffu32 << 23 || ax == 0 {
40 if (aa >> 31) != 0 || (ax >> 31) != 0 {
41 return f32::NAN;
43 }
44 if aa.wrapping_shl(1) == 0 {
45 return 1.0;
47 }
48 if ax.wrapping_shl(1) == 0 {
49 return 0.;
51 }
52 if a.is_infinite() {
53 return f32::INFINITY;
55 }
56 if x.is_infinite() {
57 return f32::INFINITY;
59 }
60 return a + f32::NAN;
61 }
62 core_gamma_pf(a, x) as f32
63}
64
65#[inline]
66pub(crate) fn core_gamma_pf(a: f32, x: f32) -> f64 {
67 const BIG: f64 = 4503599627370496.0;
68 const BIG_INV: f64 = 2.22044604925031308085e-16;
69
70 const EPS: f64 = 1e-9;
71
72 let da = a as f64;
73 let dx = x as f64;
74
75 let ax = f_fmla(da, fast_logf(x), -dx - lgamma_coref(a).0);
76 if ax <= -104. {
77 if a < x {
78 return 1.0;
79 }
80 return 0.0;
81 }
82 if ax >= 89. {
83 return f64::INFINITY;
84 }
85
86 if x <= 1.0 || x <= a {
87 let mut r2 = da;
88 let mut c2 = 1.0;
89 let mut ans2 = 1.0;
90 for _ in 0..200 {
91 r2 += 1.0;
92 c2 *= dx / r2;
93 ans2 += c2;
94
95 if c2 / ans2 <= EPS {
96 break;
97 }
98 }
99 return core_expdf(ax) * ans2 / da;
100 }
101
102 let mut y = 1.0 - da;
103 let mut z = dx + y + 1.0;
104 let mut c = 0i32;
105
106 let mut p3 = 1.0;
107 let mut q3 = dx;
108 let mut p2 = dx + 1.0;
109 let mut q2 = z * dx;
110 let mut ans = p2 / q2;
111
112 for _ in 0..200 {
113 y += 1.0;
114 z += 2.0;
115 c += 1;
116 let yc = y * c as f64;
117
118 let p = p2 * z - p3 * yc;
119 let q = q2 * z - q3 * yc;
120
121 p3 = p2;
122 p2 = p;
123 q3 = q2;
124 q2 = q;
125
126 if p.abs() > BIG {
127 p3 *= BIG_INV;
128 p2 *= BIG_INV;
129 q3 *= BIG_INV;
130 q2 *= BIG_INV;
131 }
132
133 if q != 0.0 {
134 let nextans = p / q;
135 let error = ((ans - nextans) / nextans).abs();
136 ans = nextans;
137
138 if error <= EPS {
139 break;
140 }
141 }
142 }
143
144 f_fmla(-core_expdf(ax), ans, 1.0)
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 #[test]
151 fn test_f_beta_pf() {
152 assert_eq!(f_gamma_pf(23.421, 41.), 0.9988695);
153 assert_eq!(f_gamma_pf(0.764, 0.432123), 0.47752997);
154 assert_eq!(f_gamma_pf(0.421, 1.), 0.8727869);
155 assert!(f_gamma_pf(-1., 12.).is_nan());
156 assert!(f_gamma_pf(1., -12.).is_nan());
157 assert!(f_gamma_pf(f32::NAN, 12.).is_nan());
158 assert!(f_gamma_pf(1., f32::NAN).is_nan());
159 assert_eq!(f_gamma_pf(1., f32::INFINITY), f32::INFINITY);
160 assert_eq!(f_gamma_pf(f32::INFINITY, f32::INFINITY), f32::INFINITY);
161 assert_eq!(f_gamma_pf(f32::INFINITY, 5.32), f32::INFINITY);
162 }
163}