Chris@16
|
1 // (C) Copyright John Maddock 2006.
|
Chris@16
|
2 // Use, modification and distribution are subject to the
|
Chris@16
|
3 // Boost Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
|
Chris@16
|
7 #define BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #ifdef _MSC_VER
|
Chris@16
|
10 #pragma once
|
Chris@16
|
11 #endif
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/math/tools/tuple.hpp>
|
Chris@16
|
14 #include <boost/math/special_functions/gamma.hpp>
|
Chris@16
|
15 #include <boost/math/special_functions/sign.hpp>
|
Chris@16
|
16 #include <boost/math/tools/roots.hpp>
|
Chris@16
|
17 #include <boost/math/policies/error_handling.hpp>
|
Chris@16
|
18
|
Chris@16
|
19 namespace boost{ namespace math{
|
Chris@16
|
20
|
Chris@16
|
21 namespace detail{
|
Chris@16
|
22
|
Chris@16
|
23 template <class T>
|
Chris@16
|
24 T find_inverse_s(T p, T q)
|
Chris@16
|
25 {
|
Chris@16
|
26 //
|
Chris@16
|
27 // Computation of the Incomplete Gamma Function Ratios and their Inverse
|
Chris@16
|
28 // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
Chris@16
|
29 // ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
Chris@16
|
30 // December 1986, Pages 377-393.
|
Chris@16
|
31 //
|
Chris@16
|
32 // See equation 32.
|
Chris@16
|
33 //
|
Chris@16
|
34 BOOST_MATH_STD_USING
|
Chris@16
|
35 T t;
|
Chris@16
|
36 if(p < 0.5)
|
Chris@16
|
37 {
|
Chris@16
|
38 t = sqrt(-2 * log(p));
|
Chris@16
|
39 }
|
Chris@16
|
40 else
|
Chris@16
|
41 {
|
Chris@16
|
42 t = sqrt(-2 * log(q));
|
Chris@16
|
43 }
|
Chris@16
|
44 static const double a[4] = { 3.31125922108741, 11.6616720288968, 4.28342155967104, 0.213623493715853 };
|
Chris@16
|
45 static const double b[5] = { 1, 6.61053765625462, 6.40691597760039, 1.27364489782223, 0.3611708101884203e-1 };
|
Chris@16
|
46 T s = t - tools::evaluate_polynomial(a, t) / tools::evaluate_polynomial(b, t);
|
Chris@16
|
47 if(p < 0.5)
|
Chris@16
|
48 s = -s;
|
Chris@16
|
49 return s;
|
Chris@16
|
50 }
|
Chris@16
|
51
|
Chris@16
|
52 template <class T>
|
Chris@16
|
53 T didonato_SN(T a, T x, unsigned N, T tolerance = 0)
|
Chris@16
|
54 {
|
Chris@16
|
55 //
|
Chris@16
|
56 // Computation of the Incomplete Gamma Function Ratios and their Inverse
|
Chris@16
|
57 // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
Chris@16
|
58 // ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
Chris@16
|
59 // December 1986, Pages 377-393.
|
Chris@16
|
60 //
|
Chris@16
|
61 // See equation 34.
|
Chris@16
|
62 //
|
Chris@16
|
63 T sum = 1;
|
Chris@16
|
64 if(N >= 1)
|
Chris@16
|
65 {
|
Chris@16
|
66 T partial = x / (a + 1);
|
Chris@16
|
67 sum += partial;
|
Chris@16
|
68 for(unsigned i = 2; i <= N; ++i)
|
Chris@16
|
69 {
|
Chris@16
|
70 partial *= x / (a + i);
|
Chris@16
|
71 sum += partial;
|
Chris@16
|
72 if(partial < tolerance)
|
Chris@16
|
73 break;
|
Chris@16
|
74 }
|
Chris@16
|
75 }
|
Chris@16
|
76 return sum;
|
Chris@16
|
77 }
|
Chris@16
|
78
|
Chris@16
|
79 template <class T, class Policy>
|
Chris@16
|
80 inline T didonato_FN(T p, T a, T x, unsigned N, T tolerance, const Policy& pol)
|
Chris@16
|
81 {
|
Chris@16
|
82 //
|
Chris@16
|
83 // Computation of the Incomplete Gamma Function Ratios and their Inverse
|
Chris@16
|
84 // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
Chris@16
|
85 // ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
Chris@16
|
86 // December 1986, Pages 377-393.
|
Chris@16
|
87 //
|
Chris@16
|
88 // See equation 34.
|
Chris@16
|
89 //
|
Chris@16
|
90 BOOST_MATH_STD_USING
|
Chris@16
|
91 T u = log(p) + boost::math::lgamma(a + 1, pol);
|
Chris@16
|
92 return exp((u + x - log(didonato_SN(a, x, N, tolerance))) / a);
|
Chris@16
|
93 }
|
Chris@16
|
94
|
Chris@16
|
95 template <class T, class Policy>
|
Chris@16
|
96 T find_inverse_gamma(T a, T p, T q, const Policy& pol, bool* p_has_10_digits)
|
Chris@16
|
97 {
|
Chris@16
|
98 //
|
Chris@16
|
99 // In order to understand what's going on here, you will
|
Chris@16
|
100 // need to refer to:
|
Chris@16
|
101 //
|
Chris@16
|
102 // Computation of the Incomplete Gamma Function Ratios and their Inverse
|
Chris@16
|
103 // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
Chris@16
|
104 // ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
Chris@16
|
105 // December 1986, Pages 377-393.
|
Chris@16
|
106 //
|
Chris@16
|
107 BOOST_MATH_STD_USING
|
Chris@16
|
108
|
Chris@16
|
109 T result;
|
Chris@16
|
110 *p_has_10_digits = false;
|
Chris@16
|
111
|
Chris@16
|
112 if(a == 1)
|
Chris@16
|
113 {
|
Chris@16
|
114 result = -log(q);
|
Chris@16
|
115 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
116 }
|
Chris@16
|
117 else if(a < 1)
|
Chris@16
|
118 {
|
Chris@16
|
119 T g = boost::math::tgamma(a, pol);
|
Chris@16
|
120 T b = q * g;
|
Chris@16
|
121 BOOST_MATH_INSTRUMENT_VARIABLE(g);
|
Chris@16
|
122 BOOST_MATH_INSTRUMENT_VARIABLE(b);
|
Chris@16
|
123 if((b > 0.6) || ((b >= 0.45) && (a >= 0.3)))
|
Chris@16
|
124 {
|
Chris@16
|
125 // DiDonato & Morris Eq 21:
|
Chris@16
|
126 //
|
Chris@16
|
127 // There is a slight variation from DiDonato and Morris here:
|
Chris@16
|
128 // the first form given here is unstable when p is close to 1,
|
Chris@16
|
129 // making it impossible to compute the inverse of Q(a,x) for small
|
Chris@16
|
130 // q. Fortunately the second form works perfectly well in this case.
|
Chris@16
|
131 //
|
Chris@16
|
132 T u;
|
Chris@16
|
133 if((b * q > 1e-8) && (q > 1e-5))
|
Chris@16
|
134 {
|
Chris@16
|
135 u = pow(p * g * a, 1 / a);
|
Chris@16
|
136 BOOST_MATH_INSTRUMENT_VARIABLE(u);
|
Chris@16
|
137 }
|
Chris@16
|
138 else
|
Chris@16
|
139 {
|
Chris@16
|
140 u = exp((-q / a) - constants::euler<T>());
|
Chris@16
|
141 BOOST_MATH_INSTRUMENT_VARIABLE(u);
|
Chris@16
|
142 }
|
Chris@16
|
143 result = u / (1 - (u / (a + 1)));
|
Chris@16
|
144 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
145 }
|
Chris@16
|
146 else if((a < 0.3) && (b >= 0.35))
|
Chris@16
|
147 {
|
Chris@16
|
148 // DiDonato & Morris Eq 22:
|
Chris@16
|
149 T t = exp(-constants::euler<T>() - b);
|
Chris@16
|
150 T u = t * exp(t);
|
Chris@16
|
151 result = t * exp(u);
|
Chris@16
|
152 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
153 }
|
Chris@16
|
154 else if((b > 0.15) || (a >= 0.3))
|
Chris@16
|
155 {
|
Chris@16
|
156 // DiDonato & Morris Eq 23:
|
Chris@16
|
157 T y = -log(b);
|
Chris@16
|
158 T u = y - (1 - a) * log(y);
|
Chris@16
|
159 result = y - (1 - a) * log(u) - log(1 + (1 - a) / (1 + u));
|
Chris@16
|
160 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
161 }
|
Chris@16
|
162 else if (b > 0.1)
|
Chris@16
|
163 {
|
Chris@16
|
164 // DiDonato & Morris Eq 24:
|
Chris@16
|
165 T y = -log(b);
|
Chris@16
|
166 T u = y - (1 - a) * log(y);
|
Chris@16
|
167 result = y - (1 - a) * log(u) - log((u * u + 2 * (3 - a) * u + (2 - a) * (3 - a)) / (u * u + (5 - a) * u + 2));
|
Chris@16
|
168 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
169 }
|
Chris@16
|
170 else
|
Chris@16
|
171 {
|
Chris@16
|
172 // DiDonato & Morris Eq 25:
|
Chris@16
|
173 T y = -log(b);
|
Chris@16
|
174 T c1 = (a - 1) * log(y);
|
Chris@16
|
175 T c1_2 = c1 * c1;
|
Chris@16
|
176 T c1_3 = c1_2 * c1;
|
Chris@16
|
177 T c1_4 = c1_2 * c1_2;
|
Chris@16
|
178 T a_2 = a * a;
|
Chris@16
|
179 T a_3 = a_2 * a;
|
Chris@16
|
180
|
Chris@16
|
181 T c2 = (a - 1) * (1 + c1);
|
Chris@16
|
182 T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2);
|
Chris@16
|
183 T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6);
|
Chris@16
|
184 T c5 = (a - 1) * (-(c1_4 / 4)
|
Chris@16
|
185 + (11 * a - 17) * c1_3 / 6
|
Chris@16
|
186 + (-3 * a_2 + 13 * a -13) * c1_2
|
Chris@16
|
187 + (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2
|
Chris@16
|
188 + (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12);
|
Chris@16
|
189
|
Chris@16
|
190 T y_2 = y * y;
|
Chris@16
|
191 T y_3 = y_2 * y;
|
Chris@16
|
192 T y_4 = y_2 * y_2;
|
Chris@16
|
193 result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4);
|
Chris@16
|
194 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
195 if(b < 1e-28f)
|
Chris@16
|
196 *p_has_10_digits = true;
|
Chris@16
|
197 }
|
Chris@16
|
198 }
|
Chris@16
|
199 else
|
Chris@16
|
200 {
|
Chris@16
|
201 // DiDonato and Morris Eq 31:
|
Chris@16
|
202 T s = find_inverse_s(p, q);
|
Chris@16
|
203
|
Chris@16
|
204 BOOST_MATH_INSTRUMENT_VARIABLE(s);
|
Chris@16
|
205
|
Chris@16
|
206 T s_2 = s * s;
|
Chris@16
|
207 T s_3 = s_2 * s;
|
Chris@16
|
208 T s_4 = s_2 * s_2;
|
Chris@16
|
209 T s_5 = s_4 * s;
|
Chris@16
|
210 T ra = sqrt(a);
|
Chris@16
|
211
|
Chris@16
|
212 BOOST_MATH_INSTRUMENT_VARIABLE(ra);
|
Chris@16
|
213
|
Chris@16
|
214 T w = a + s * ra + (s * s -1) / 3;
|
Chris@16
|
215 w += (s_3 - 7 * s) / (36 * ra);
|
Chris@16
|
216 w -= (3 * s_4 + 7 * s_2 - 16) / (810 * a);
|
Chris@16
|
217 w += (9 * s_5 + 256 * s_3 - 433 * s) / (38880 * a * ra);
|
Chris@16
|
218
|
Chris@16
|
219 BOOST_MATH_INSTRUMENT_VARIABLE(w);
|
Chris@16
|
220
|
Chris@16
|
221 if((a >= 500) && (fabs(1 - w / a) < 1e-6))
|
Chris@16
|
222 {
|
Chris@16
|
223 result = w;
|
Chris@16
|
224 *p_has_10_digits = true;
|
Chris@16
|
225 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
226 }
|
Chris@16
|
227 else if (p > 0.5)
|
Chris@16
|
228 {
|
Chris@16
|
229 if(w < 3 * a)
|
Chris@16
|
230 {
|
Chris@16
|
231 result = w;
|
Chris@16
|
232 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
233 }
|
Chris@16
|
234 else
|
Chris@16
|
235 {
|
Chris@16
|
236 T D = (std::max)(T(2), T(a * (a - 1)));
|
Chris@16
|
237 T lg = boost::math::lgamma(a, pol);
|
Chris@16
|
238 T lb = log(q) + lg;
|
Chris@16
|
239 if(lb < -D * 2.3)
|
Chris@16
|
240 {
|
Chris@16
|
241 // DiDonato and Morris Eq 25:
|
Chris@16
|
242 T y = -lb;
|
Chris@16
|
243 T c1 = (a - 1) * log(y);
|
Chris@16
|
244 T c1_2 = c1 * c1;
|
Chris@16
|
245 T c1_3 = c1_2 * c1;
|
Chris@16
|
246 T c1_4 = c1_2 * c1_2;
|
Chris@16
|
247 T a_2 = a * a;
|
Chris@16
|
248 T a_3 = a_2 * a;
|
Chris@16
|
249
|
Chris@16
|
250 T c2 = (a - 1) * (1 + c1);
|
Chris@16
|
251 T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2);
|
Chris@16
|
252 T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6);
|
Chris@16
|
253 T c5 = (a - 1) * (-(c1_4 / 4)
|
Chris@16
|
254 + (11 * a - 17) * c1_3 / 6
|
Chris@16
|
255 + (-3 * a_2 + 13 * a -13) * c1_2
|
Chris@16
|
256 + (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2
|
Chris@16
|
257 + (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12);
|
Chris@16
|
258
|
Chris@16
|
259 T y_2 = y * y;
|
Chris@16
|
260 T y_3 = y_2 * y;
|
Chris@16
|
261 T y_4 = y_2 * y_2;
|
Chris@16
|
262 result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4);
|
Chris@16
|
263 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
264 }
|
Chris@16
|
265 else
|
Chris@16
|
266 {
|
Chris@16
|
267 // DiDonato and Morris Eq 33:
|
Chris@16
|
268 T u = -lb + (a - 1) * log(w) - log(1 + (1 - a) / (1 + w));
|
Chris@16
|
269 result = -lb + (a - 1) * log(u) - log(1 + (1 - a) / (1 + u));
|
Chris@16
|
270 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
271 }
|
Chris@16
|
272 }
|
Chris@16
|
273 }
|
Chris@16
|
274 else
|
Chris@16
|
275 {
|
Chris@16
|
276 T z = w;
|
Chris@16
|
277 T ap1 = a + 1;
|
Chris@16
|
278 T ap2 = a + 2;
|
Chris@16
|
279 if(w < 0.15f * ap1)
|
Chris@16
|
280 {
|
Chris@16
|
281 // DiDonato and Morris Eq 35:
|
Chris@16
|
282 T v = log(p) + boost::math::lgamma(ap1, pol);
|
Chris@16
|
283 z = exp((v + w) / a);
|
Chris@101
|
284 s = boost::math::log1p(z / ap1 * (1 + z / ap2), pol);
|
Chris@16
|
285 z = exp((v + z - s) / a);
|
Chris@101
|
286 s = boost::math::log1p(z / ap1 * (1 + z / ap2), pol);
|
Chris@16
|
287 z = exp((v + z - s) / a);
|
Chris@101
|
288 s = boost::math::log1p(z / ap1 * (1 + z / ap2 * (1 + z / (a + 3))), pol);
|
Chris@16
|
289 z = exp((v + z - s) / a);
|
Chris@16
|
290 BOOST_MATH_INSTRUMENT_VARIABLE(z);
|
Chris@16
|
291 }
|
Chris@16
|
292
|
Chris@16
|
293 if((z <= 0.01 * ap1) || (z > 0.7 * ap1))
|
Chris@16
|
294 {
|
Chris@16
|
295 result = z;
|
Chris@16
|
296 if(z <= 0.002 * ap1)
|
Chris@16
|
297 *p_has_10_digits = true;
|
Chris@16
|
298 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
299 }
|
Chris@16
|
300 else
|
Chris@16
|
301 {
|
Chris@16
|
302 // DiDonato and Morris Eq 36:
|
Chris@16
|
303 T ls = log(didonato_SN(a, z, 100, T(1e-4)));
|
Chris@16
|
304 T v = log(p) + boost::math::lgamma(ap1, pol);
|
Chris@16
|
305 z = exp((v + z - ls) / a);
|
Chris@16
|
306 result = z * (1 - (a * log(z) - z - v + ls) / (a - z));
|
Chris@16
|
307
|
Chris@16
|
308 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
309 }
|
Chris@16
|
310 }
|
Chris@16
|
311 }
|
Chris@16
|
312 return result;
|
Chris@16
|
313 }
|
Chris@16
|
314
|
Chris@16
|
315 template <class T, class Policy>
|
Chris@16
|
316 struct gamma_p_inverse_func
|
Chris@16
|
317 {
|
Chris@16
|
318 gamma_p_inverse_func(T a_, T p_, bool inv) : a(a_), p(p_), invert(inv)
|
Chris@16
|
319 {
|
Chris@16
|
320 //
|
Chris@16
|
321 // If p is too near 1 then P(x) - p suffers from cancellation
|
Chris@16
|
322 // errors causing our root-finding algorithms to "thrash", better
|
Chris@16
|
323 // to invert in this case and calculate Q(x) - (1-p) instead.
|
Chris@16
|
324 //
|
Chris@16
|
325 // Of course if p is *very* close to 1, then the answer we get will
|
Chris@16
|
326 // be inaccurate anyway (because there's not enough information in p)
|
Chris@16
|
327 // but at least we will converge on the (inaccurate) answer quickly.
|
Chris@16
|
328 //
|
Chris@16
|
329 if(p > 0.9)
|
Chris@16
|
330 {
|
Chris@16
|
331 p = 1 - p;
|
Chris@16
|
332 invert = !invert;
|
Chris@16
|
333 }
|
Chris@16
|
334 }
|
Chris@16
|
335
|
Chris@16
|
336 boost::math::tuple<T, T, T> operator()(const T& x)const
|
Chris@16
|
337 {
|
Chris@16
|
338 BOOST_FPU_EXCEPTION_GUARD
|
Chris@16
|
339 //
|
Chris@16
|
340 // Calculate P(x) - p and the first two derivates, or if the invert
|
Chris@16
|
341 // flag is set, then Q(x) - q and it's derivatives.
|
Chris@16
|
342 //
|
Chris@16
|
343 typedef typename policies::evaluation<T, Policy>::type value_type;
|
Chris@16
|
344 // typedef typename lanczos::lanczos<T, Policy>::type evaluation_type;
|
Chris@16
|
345 typedef typename policies::normalise<
|
Chris@16
|
346 Policy,
|
Chris@16
|
347 policies::promote_float<false>,
|
Chris@16
|
348 policies::promote_double<false>,
|
Chris@16
|
349 policies::discrete_quantile<>,
|
Chris@16
|
350 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
351
|
Chris@16
|
352 BOOST_MATH_STD_USING // For ADL of std functions.
|
Chris@16
|
353
|
Chris@16
|
354 T f, f1;
|
Chris@16
|
355 value_type ft;
|
Chris@16
|
356 f = static_cast<T>(boost::math::detail::gamma_incomplete_imp(
|
Chris@16
|
357 static_cast<value_type>(a),
|
Chris@16
|
358 static_cast<value_type>(x),
|
Chris@16
|
359 true, invert,
|
Chris@16
|
360 forwarding_policy(), &ft));
|
Chris@16
|
361 f1 = static_cast<T>(ft);
|
Chris@16
|
362 T f2;
|
Chris@16
|
363 T div = (a - x - 1) / x;
|
Chris@16
|
364 f2 = f1;
|
Chris@16
|
365 if((fabs(div) > 1) && (tools::max_value<T>() / fabs(div) < f2))
|
Chris@16
|
366 {
|
Chris@16
|
367 // overflow:
|
Chris@16
|
368 f2 = -tools::max_value<T>() / 2;
|
Chris@16
|
369 }
|
Chris@16
|
370 else
|
Chris@16
|
371 {
|
Chris@16
|
372 f2 *= div;
|
Chris@16
|
373 }
|
Chris@16
|
374
|
Chris@16
|
375 if(invert)
|
Chris@16
|
376 {
|
Chris@16
|
377 f1 = -f1;
|
Chris@16
|
378 f2 = -f2;
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 return boost::math::make_tuple(static_cast<T>(f - p), f1, f2);
|
Chris@16
|
382 }
|
Chris@16
|
383 private:
|
Chris@16
|
384 T a, p;
|
Chris@16
|
385 bool invert;
|
Chris@16
|
386 };
|
Chris@16
|
387
|
Chris@16
|
388 template <class T, class Policy>
|
Chris@16
|
389 T gamma_p_inv_imp(T a, T p, const Policy& pol)
|
Chris@16
|
390 {
|
Chris@16
|
391 BOOST_MATH_STD_USING // ADL of std functions.
|
Chris@16
|
392
|
Chris@16
|
393 static const char* function = "boost::math::gamma_p_inv<%1%>(%1%, %1%)";
|
Chris@16
|
394
|
Chris@16
|
395 BOOST_MATH_INSTRUMENT_VARIABLE(a);
|
Chris@16
|
396 BOOST_MATH_INSTRUMENT_VARIABLE(p);
|
Chris@16
|
397
|
Chris@16
|
398 if(a <= 0)
|
Chris@101
|
399 return policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
|
Chris@16
|
400 if((p < 0) || (p > 1))
|
Chris@101
|
401 return policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got p=%1%).", p, pol);
|
Chris@16
|
402 if(p == 1)
|
Chris@101
|
403 return policies::raise_overflow_error<T>(function, 0, Policy());
|
Chris@16
|
404 if(p == 0)
|
Chris@16
|
405 return 0;
|
Chris@16
|
406 bool has_10_digits;
|
Chris@16
|
407 T guess = detail::find_inverse_gamma<T>(a, p, 1 - p, pol, &has_10_digits);
|
Chris@16
|
408 if((policies::digits<T, Policy>() <= 36) && has_10_digits)
|
Chris@16
|
409 return guess;
|
Chris@16
|
410 T lower = tools::min_value<T>();
|
Chris@16
|
411 if(guess <= lower)
|
Chris@16
|
412 guess = tools::min_value<T>();
|
Chris@16
|
413 BOOST_MATH_INSTRUMENT_VARIABLE(guess);
|
Chris@16
|
414 //
|
Chris@16
|
415 // Work out how many digits to converge to, normally this is
|
Chris@16
|
416 // 2/3 of the digits in T, but if the first derivative is very
|
Chris@16
|
417 // large convergence is slow, so we'll bump it up to full
|
Chris@16
|
418 // precision to prevent premature termination of the root-finding routine.
|
Chris@16
|
419 //
|
Chris@16
|
420 unsigned digits = policies::digits<T, Policy>();
|
Chris@16
|
421 if(digits < 30)
|
Chris@16
|
422 {
|
Chris@16
|
423 digits *= 2;
|
Chris@16
|
424 digits /= 3;
|
Chris@16
|
425 }
|
Chris@16
|
426 else
|
Chris@16
|
427 {
|
Chris@16
|
428 digits /= 2;
|
Chris@16
|
429 digits -= 1;
|
Chris@16
|
430 }
|
Chris@16
|
431 if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
|
Chris@16
|
432 digits = policies::digits<T, Policy>() - 2;
|
Chris@16
|
433 //
|
Chris@16
|
434 // Go ahead and iterate:
|
Chris@16
|
435 //
|
Chris@16
|
436 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
437 guess = tools::halley_iterate(
|
Chris@16
|
438 detail::gamma_p_inverse_func<T, Policy>(a, p, false),
|
Chris@16
|
439 guess,
|
Chris@16
|
440 lower,
|
Chris@16
|
441 tools::max_value<T>(),
|
Chris@16
|
442 digits,
|
Chris@16
|
443 max_iter);
|
Chris@16
|
444 policies::check_root_iterations<T>(function, max_iter, pol);
|
Chris@16
|
445 BOOST_MATH_INSTRUMENT_VARIABLE(guess);
|
Chris@16
|
446 if(guess == lower)
|
Chris@16
|
447 guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
|
Chris@16
|
448 return guess;
|
Chris@16
|
449 }
|
Chris@16
|
450
|
Chris@16
|
451 template <class T, class Policy>
|
Chris@16
|
452 T gamma_q_inv_imp(T a, T q, const Policy& pol)
|
Chris@16
|
453 {
|
Chris@16
|
454 BOOST_MATH_STD_USING // ADL of std functions.
|
Chris@16
|
455
|
Chris@16
|
456 static const char* function = "boost::math::gamma_q_inv<%1%>(%1%, %1%)";
|
Chris@16
|
457
|
Chris@16
|
458 if(a <= 0)
|
Chris@101
|
459 return policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
|
Chris@16
|
460 if((q < 0) || (q > 1))
|
Chris@101
|
461 return policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got q=%1%).", q, pol);
|
Chris@16
|
462 if(q == 0)
|
Chris@101
|
463 return policies::raise_overflow_error<T>(function, 0, Policy());
|
Chris@16
|
464 if(q == 1)
|
Chris@16
|
465 return 0;
|
Chris@16
|
466 bool has_10_digits;
|
Chris@16
|
467 T guess = detail::find_inverse_gamma<T>(a, 1 - q, q, pol, &has_10_digits);
|
Chris@16
|
468 if((policies::digits<T, Policy>() <= 36) && has_10_digits)
|
Chris@16
|
469 return guess;
|
Chris@16
|
470 T lower = tools::min_value<T>();
|
Chris@16
|
471 if(guess <= lower)
|
Chris@16
|
472 guess = tools::min_value<T>();
|
Chris@16
|
473 //
|
Chris@16
|
474 // Work out how many digits to converge to, normally this is
|
Chris@16
|
475 // 2/3 of the digits in T, but if the first derivative is very
|
Chris@16
|
476 // large convergence is slow, so we'll bump it up to full
|
Chris@16
|
477 // precision to prevent premature termination of the root-finding routine.
|
Chris@16
|
478 //
|
Chris@16
|
479 unsigned digits = policies::digits<T, Policy>();
|
Chris@16
|
480 if(digits < 30)
|
Chris@16
|
481 {
|
Chris@16
|
482 digits *= 2;
|
Chris@16
|
483 digits /= 3;
|
Chris@16
|
484 }
|
Chris@16
|
485 else
|
Chris@16
|
486 {
|
Chris@16
|
487 digits /= 2;
|
Chris@16
|
488 digits -= 1;
|
Chris@16
|
489 }
|
Chris@16
|
490 if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
|
Chris@16
|
491 digits = policies::digits<T, Policy>();
|
Chris@16
|
492 //
|
Chris@16
|
493 // Go ahead and iterate:
|
Chris@16
|
494 //
|
Chris@16
|
495 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
496 guess = tools::halley_iterate(
|
Chris@16
|
497 detail::gamma_p_inverse_func<T, Policy>(a, q, true),
|
Chris@16
|
498 guess,
|
Chris@16
|
499 lower,
|
Chris@16
|
500 tools::max_value<T>(),
|
Chris@16
|
501 digits,
|
Chris@16
|
502 max_iter);
|
Chris@16
|
503 policies::check_root_iterations<T>(function, max_iter, pol);
|
Chris@16
|
504 if(guess == lower)
|
Chris@16
|
505 guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
|
Chris@16
|
506 return guess;
|
Chris@16
|
507 }
|
Chris@16
|
508
|
Chris@16
|
509 } // namespace detail
|
Chris@16
|
510
|
Chris@16
|
511 template <class T1, class T2, class Policy>
|
Chris@16
|
512 inline typename tools::promote_args<T1, T2>::type
|
Chris@16
|
513 gamma_p_inv(T1 a, T2 p, const Policy& pol)
|
Chris@16
|
514 {
|
Chris@16
|
515 typedef typename tools::promote_args<T1, T2>::type result_type;
|
Chris@16
|
516 return detail::gamma_p_inv_imp(
|
Chris@16
|
517 static_cast<result_type>(a),
|
Chris@16
|
518 static_cast<result_type>(p), pol);
|
Chris@16
|
519 }
|
Chris@16
|
520
|
Chris@16
|
521 template <class T1, class T2, class Policy>
|
Chris@16
|
522 inline typename tools::promote_args<T1, T2>::type
|
Chris@16
|
523 gamma_q_inv(T1 a, T2 p, const Policy& pol)
|
Chris@16
|
524 {
|
Chris@16
|
525 typedef typename tools::promote_args<T1, T2>::type result_type;
|
Chris@16
|
526 return detail::gamma_q_inv_imp(
|
Chris@16
|
527 static_cast<result_type>(a),
|
Chris@16
|
528 static_cast<result_type>(p), pol);
|
Chris@16
|
529 }
|
Chris@16
|
530
|
Chris@16
|
531 template <class T1, class T2>
|
Chris@16
|
532 inline typename tools::promote_args<T1, T2>::type
|
Chris@16
|
533 gamma_p_inv(T1 a, T2 p)
|
Chris@16
|
534 {
|
Chris@16
|
535 return gamma_p_inv(a, p, policies::policy<>());
|
Chris@16
|
536 }
|
Chris@16
|
537
|
Chris@16
|
538 template <class T1, class T2>
|
Chris@16
|
539 inline typename tools::promote_args<T1, T2>::type
|
Chris@16
|
540 gamma_q_inv(T1 a, T2 p)
|
Chris@16
|
541 {
|
Chris@16
|
542 return gamma_q_inv(a, p, policies::policy<>());
|
Chris@16
|
543 }
|
Chris@16
|
544
|
Chris@16
|
545 } // namespace math
|
Chris@16
|
546 } // namespace boost
|
Chris@16
|
547
|
Chris@16
|
548 #endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
|
Chris@16
|
549
|
Chris@16
|
550
|
Chris@16
|
551
|