annotate DEPENDENCIES/generic/include/boost/math/special_functions/detail/igamma_inverse.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
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