igamma_inverse.hpp 18 KB

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