t_distribution_inv.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // Copyright John Maddock 2007.
  2. // Copyright Paul A. Bristow 2007
  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_SF_DETAIL_INV_T_HPP
  7. #define BOOST_MATH_SF_DETAIL_INV_T_HPP
  8. #ifdef _MSC_VER
  9. #pragma once
  10. #endif
  11. #include <boost/math/special_functions/cbrt.hpp>
  12. #include <boost/math/special_functions/round.hpp>
  13. #include <boost/math/special_functions/trunc.hpp>
  14. namespace boost{ namespace math{ namespace detail{
  15. //
  16. // The main method used is due to Hill:
  17. //
  18. // G. W. Hill, Algorithm 396, Student's t-Quantiles,
  19. // Communications of the ACM, 13(10): 619-620, Oct., 1970.
  20. //
  21. template <class T, class Policy>
  22. T inverse_students_t_hill(T ndf, T u, const Policy& pol)
  23. {
  24. BOOST_MATH_STD_USING
  25. BOOST_MATH_ASSERT(u <= 0.5);
  26. T a, b, c, d, q, x, y;
  27. if (ndf > 1e20f)
  28. return -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
  29. a = 1 / (ndf - 0.5f);
  30. b = 48 / (a * a);
  31. c = ((20700 * a / b - 98) * a - 16) * a + 96.36f;
  32. d = ((94.5f / (b + c) - 3) / b + 1) * sqrt(a * constants::pi<T>() / 2) * ndf;
  33. y = pow(d * 2 * u, 2 / ndf);
  34. if (y > (0.05f + a))
  35. {
  36. //
  37. // Asymptotic inverse expansion about normal:
  38. //
  39. x = -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
  40. y = x * x;
  41. if (ndf < 5)
  42. c += 0.3f * (ndf - 4.5f) * (x + 0.6f);
  43. c += (((0.05f * d * x - 5) * x - 7) * x - 2) * x + b;
  44. y = (((((0.4f * y + 6.3f) * y + 36) * y + 94.5f) / c - y - 3) / b + 1) * x;
  45. y = boost::math::expm1(a * y * y, pol);
  46. }
  47. else
  48. {
  49. y = static_cast<T>(((1 / (((ndf + 6) / (ndf * y) - 0.089f * d - 0.822f)
  50. * (ndf + 2) * 3) + 0.5 / (ndf + 4)) * y - 1)
  51. * (ndf + 1) / (ndf + 2) + 1 / y);
  52. }
  53. q = sqrt(ndf * y);
  54. return -q;
  55. }
  56. //
  57. // Tail and body series are due to Shaw:
  58. //
  59. // www.mth.kcl.ac.uk/~shaww/web_page/papers/Tdistribution06.pdf
  60. //
  61. // Shaw, W.T., 2006, "Sampling Student's T distribution - use of
  62. // the inverse cumulative distribution function."
  63. // Journal of Computational Finance, Vol 9 Issue 4, pp 37-73, Summer 2006
  64. //
  65. template <class T, class Policy>
  66. T inverse_students_t_tail_series(T df, T v, const Policy& pol)
  67. {
  68. BOOST_MATH_STD_USING
  69. // Tail series expansion, see section 6 of Shaw's paper.
  70. // w is calculated using Eq 60:
  71. T w = boost::math::tgamma_delta_ratio(df / 2, constants::half<T>(), pol)
  72. * sqrt(df * constants::pi<T>()) * v;
  73. // define some variables:
  74. T np2 = df + 2;
  75. T np4 = df + 4;
  76. T np6 = df + 6;
  77. //
  78. // Calculate the coefficients d(k), these depend only on the
  79. // number of degrees of freedom df, so at least in theory
  80. // we could tabulate these for fixed df, see p15 of Shaw:
  81. //
  82. T d[7] = { 1, };
  83. d[1] = -(df + 1) / (2 * np2);
  84. np2 *= (df + 2);
  85. d[2] = -df * (df + 1) * (df + 3) / (8 * np2 * np4);
  86. np2 *= df + 2;
  87. d[3] = -df * (df + 1) * (df + 5) * (((3 * df) + 7) * df -2) / (48 * np2 * np4 * np6);
  88. np2 *= (df + 2);
  89. np4 *= (df + 4);
  90. d[4] = -df * (df + 1) * (df + 7) *
  91. ( (((((15 * df) + 154) * df + 465) * df + 286) * df - 336) * df + 64 )
  92. / (384 * np2 * np4 * np6 * (df + 8));
  93. np2 *= (df + 2);
  94. d[5] = -df * (df + 1) * (df + 3) * (df + 9)
  95. * (((((((35 * df + 452) * df + 1573) * df + 600) * df - 2020) * df) + 928) * df -128)
  96. / (1280 * np2 * np4 * np6 * (df + 8) * (df + 10));
  97. np2 *= (df + 2);
  98. np4 *= (df + 4);
  99. np6 *= (df + 6);
  100. d[6] = -df * (df + 1) * (df + 11)
  101. * ((((((((((((945 * df) + 31506) * df + 425858) * df + 2980236) * df + 11266745) * df + 20675018) * df + 7747124) * df - 22574632) * df - 8565600) * df + 18108416) * df - 7099392) * df + 884736)
  102. / (46080 * np2 * np4 * np6 * (df + 8) * (df + 10) * (df +12));
  103. //
  104. // Now bring everything together to provide the result,
  105. // this is Eq 62 of Shaw:
  106. //
  107. T rn = sqrt(df);
  108. T div = pow(rn * w, 1 / df);
  109. T power = div * div;
  110. T result = tools::evaluate_polynomial<7, T, T>(d, power);
  111. result *= rn;
  112. result /= div;
  113. return -result;
  114. }
  115. template <class T, class Policy>
  116. T inverse_students_t_body_series(T df, T u, const Policy& pol)
  117. {
  118. BOOST_MATH_STD_USING
  119. //
  120. // Body series for small N:
  121. //
  122. // Start with Eq 56 of Shaw:
  123. //
  124. T v = boost::math::tgamma_delta_ratio(df / 2, constants::half<T>(), pol)
  125. * sqrt(df * constants::pi<T>()) * (u - constants::half<T>());
  126. //
  127. // Workspace for the polynomial coefficients:
  128. //
  129. T c[11] = { 0, 1, };
  130. //
  131. // Figure out what the coefficients are, note these depend
  132. // only on the degrees of freedom (Eq 57 of Shaw):
  133. //
  134. T in = 1 / df;
  135. c[2] = static_cast<T>(0.16666666666666666667 + 0.16666666666666666667 * in);
  136. c[3] = static_cast<T>((0.0083333333333333333333 * in
  137. + 0.066666666666666666667) * in
  138. + 0.058333333333333333333);
  139. c[4] = static_cast<T>(((0.00019841269841269841270 * in
  140. + 0.0017857142857142857143) * in
  141. + 0.026785714285714285714) * in
  142. + 0.025198412698412698413);
  143. c[5] = static_cast<T>((((2.7557319223985890653e-6 * in
  144. + 0.00037477954144620811287) * in
  145. - 0.0011078042328042328042) * in
  146. + 0.010559964726631393298) * in
  147. + 0.012039792768959435626);
  148. c[6] = static_cast<T>(((((2.5052108385441718775e-8 * in
  149. - 0.000062705427288760622094) * in
  150. + 0.00059458674042007375341) * in
  151. - 0.0016095979637646304313) * in
  152. + 0.0061039211560044893378) * in
  153. + 0.0038370059724226390893);
  154. c[7] = static_cast<T>((((((1.6059043836821614599e-10 * in
  155. + 0.000015401265401265401265) * in
  156. - 0.00016376804137220803887) * in
  157. + 0.00069084207973096861986) * in
  158. - 0.0012579159844784844785) * in
  159. + 0.0010898206731540064873) * in
  160. + 0.0032177478835464946576);
  161. c[8] = static_cast<T>(((((((7.6471637318198164759e-13 * in
  162. - 3.9851014346715404916e-6) * in
  163. + 0.000049255746366361445727) * in
  164. - 0.00024947258047043099953) * in
  165. + 0.00064513046951456342991) * in
  166. - 0.00076245135440323932387) * in
  167. + 0.000033530976880017885309) * in
  168. + 0.0017438262298340009980);
  169. c[9] = static_cast<T>((((((((2.8114572543455207632e-15 * in
  170. + 1.0914179173496789432e-6) * in
  171. - 0.000015303004486655377567) * in
  172. + 0.000090867107935219902229) * in
  173. - 0.00029133414466938067350) * in
  174. + 0.00051406605788341121363) * in
  175. - 0.00036307660358786885787) * in
  176. - 0.00031101086326318780412) * in
  177. + 0.00096472747321388644237);
  178. c[10] = static_cast<T>(((((((((8.2206352466243297170e-18 * in
  179. - 3.1239569599829868045e-7) * in
  180. + 4.8903045291975346210e-6) * in
  181. - 0.000033202652391372058698) * in
  182. + 0.00012645437628698076975) * in
  183. - 0.00028690924218514613987) * in
  184. + 0.00035764655430568632777) * in
  185. - 0.00010230378073700412687) * in
  186. - 0.00036942667800009661203) * in
  187. + 0.00054229262813129686486);
  188. //
  189. // The result is then a polynomial in v (see Eq 56 of Shaw):
  190. //
  191. return tools::evaluate_odd_polynomial<11, T, T>(c, v);
  192. }
  193. template <class T, class Policy>
  194. T inverse_students_t(T df, T u, T v, const Policy& pol, bool* pexact = nullptr)
  195. {
  196. //
  197. // df = number of degrees of freedom.
  198. // u = probability.
  199. // v = 1 - u.
  200. // l = lanczos type to use.
  201. //
  202. BOOST_MATH_STD_USING
  203. bool invert = false;
  204. T result = 0;
  205. if(pexact)
  206. *pexact = false;
  207. if(u > v)
  208. {
  209. // function is symmetric, invert it:
  210. std::swap(u, v);
  211. invert = true;
  212. }
  213. if((floor(df) == df) && (df < 20))
  214. {
  215. //
  216. // we have integer degrees of freedom, try for the special
  217. // cases first:
  218. //
  219. T tolerance = ldexp(1.0f, (2 * policies::digits<T, Policy>()) / 3);
  220. switch(itrunc(df, Policy()))
  221. {
  222. case 1:
  223. {
  224. //
  225. // df = 1 is the same as the Cauchy distribution, see
  226. // Shaw Eq 35:
  227. //
  228. if(u == 0.5)
  229. result = 0;
  230. else
  231. result = -cos(constants::pi<T>() * u) / sin(constants::pi<T>() * u);
  232. if(pexact)
  233. *pexact = true;
  234. break;
  235. }
  236. case 2:
  237. {
  238. //
  239. // df = 2 has an exact result, see Shaw Eq 36:
  240. //
  241. result =(2 * u - 1) / sqrt(2 * u * v);
  242. if(pexact)
  243. *pexact = true;
  244. break;
  245. }
  246. case 4:
  247. {
  248. //
  249. // df = 4 has an exact result, see Shaw Eq 38 & 39:
  250. //
  251. T alpha = 4 * u * v;
  252. T root_alpha = sqrt(alpha);
  253. T r = 4 * cos(acos(root_alpha) / 3) / root_alpha;
  254. T x = sqrt(r - 4);
  255. result = u - 0.5f < 0 ? (T)-x : x;
  256. if(pexact)
  257. *pexact = true;
  258. break;
  259. }
  260. case 6:
  261. {
  262. //
  263. // We get numeric overflow in this area:
  264. //
  265. if(u < 1e-150)
  266. return (invert ? -1 : 1) * inverse_students_t_hill(df, u, pol);
  267. //
  268. // Newton-Raphson iteration of a polynomial case,
  269. // choice of seed value is taken from Shaw's online
  270. // supplement:
  271. //
  272. T a = 4 * (u - u * u);//1 - 4 * (u - 0.5f) * (u - 0.5f);
  273. T b = boost::math::cbrt(a, pol);
  274. static const T c = static_cast<T>(0.85498797333834849467655443627193);
  275. T p = 6 * (1 + c * (1 / b - 1));
  276. T p0;
  277. do{
  278. T p2 = p * p;
  279. T p4 = p2 * p2;
  280. T p5 = p * p4;
  281. p0 = p;
  282. // next term is given by Eq 41:
  283. p = 2 * (8 * a * p5 - 270 * p2 + 2187) / (5 * (4 * a * p4 - 216 * p - 243));
  284. }while(fabs((p - p0) / p) > tolerance);
  285. //
  286. // Use Eq 45 to extract the result:
  287. //
  288. p = sqrt(p - df);
  289. result = (u - 0.5f) < 0 ? (T)-p : p;
  290. break;
  291. }
  292. #if 0
  293. //
  294. // These are Shaw's "exact" but iterative solutions
  295. // for even df, the numerical accuracy of these is
  296. // rather less than Hill's method, so these are disabled
  297. // for now, which is a shame because they are reasonably
  298. // quick to evaluate...
  299. //
  300. case 8:
  301. {
  302. //
  303. // Newton-Raphson iteration of a polynomial case,
  304. // choice of seed value is taken from Shaw's online
  305. // supplement:
  306. //
  307. static const T c8 = 0.85994765706259820318168359251872L;
  308. T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
  309. T b = pow(a, T(1) / 4);
  310. T p = 8 * (1 + c8 * (1 / b - 1));
  311. T p0 = p;
  312. do{
  313. T p5 = p * p;
  314. p5 *= p5 * p;
  315. p0 = p;
  316. // Next term is given by Eq 42:
  317. p = 2 * (3 * p + (640 * (160 + p * (24 + p * (p + 4)))) / (-5120 + p * (-2048 - 960 * p + a * p5))) / 7;
  318. }while(fabs((p - p0) / p) > tolerance);
  319. //
  320. // Use Eq 45 to extract the result:
  321. //
  322. p = sqrt(p - df);
  323. result = (u - 0.5f) < 0 ? -p : p;
  324. break;
  325. }
  326. case 10:
  327. {
  328. //
  329. // Newton-Raphson iteration of a polynomial case,
  330. // choice of seed value is taken from Shaw's online
  331. // supplement:
  332. //
  333. static const T c10 = 0.86781292867813396759105692122285L;
  334. T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
  335. T b = pow(a, T(1) / 5);
  336. T p = 10 * (1 + c10 * (1 / b - 1));
  337. T p0;
  338. do{
  339. T p6 = p * p;
  340. p6 *= p6 * p6;
  341. p0 = p;
  342. // Next term given by Eq 43:
  343. p = (8 * p) / 9 + (218750 * (21875 + 4 * p * (625 + p * (75 + 2 * p * (5 + p))))) /
  344. (9 * (-68359375 + 8 * p * (-2343750 + p * (-546875 - 175000 * p + 8 * a * p6))));
  345. }while(fabs((p - p0) / p) > tolerance);
  346. //
  347. // Use Eq 45 to extract the result:
  348. //
  349. p = sqrt(p - df);
  350. result = (u - 0.5f) < 0 ? -p : p;
  351. break;
  352. }
  353. #endif
  354. default:
  355. goto calculate_real;
  356. }
  357. }
  358. else
  359. {
  360. calculate_real:
  361. if(df > 0x10000000)
  362. {
  363. result = -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
  364. if((pexact) && (df >= 1e20))
  365. *pexact = true;
  366. }
  367. else if(df < 3)
  368. {
  369. //
  370. // Use a roughly linear scheme to choose between Shaw's
  371. // tail series and body series:
  372. //
  373. T crossover = 0.2742f - df * 0.0242143f;
  374. if(u > crossover)
  375. {
  376. result = boost::math::detail::inverse_students_t_body_series(df, u, pol);
  377. }
  378. else
  379. {
  380. result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
  381. }
  382. }
  383. else
  384. {
  385. //
  386. // Use Hill's method except in the extreme tails
  387. // where we use Shaw's tail series.
  388. // The crossover point is roughly exponential in -df:
  389. //
  390. T crossover = ldexp(1.0f, iround(T(df / -0.654f), typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type()));
  391. if(u > crossover)
  392. {
  393. result = boost::math::detail::inverse_students_t_hill(df, u, pol);
  394. }
  395. else
  396. {
  397. result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
  398. }
  399. }
  400. }
  401. return invert ? (T)-result : result;
  402. }
  403. template <class T, class Policy>
  404. inline T find_ibeta_inv_from_t_dist(T a, T p, T /*q*/, T* py, const Policy& pol)
  405. {
  406. T u = p / 2;
  407. T v = 1 - u;
  408. T df = a * 2;
  409. T t = boost::math::detail::inverse_students_t(df, u, v, pol);
  410. *py = t * t / (df + t * t);
  411. return df / (df + t * t);
  412. }
  413. template <class T, class Policy>
  414. inline T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const std::false_type*)
  415. {
  416. BOOST_MATH_STD_USING
  417. //
  418. // Need to use inverse incomplete beta to get
  419. // required precision so not so fast:
  420. //
  421. T probability = (p > 0.5) ? 1 - p : p;
  422. T t, x, y(0);
  423. x = ibeta_inv(df / 2, T(0.5), 2 * probability, &y, pol);
  424. if(df * y > tools::max_value<T>() * x)
  425. t = policies::raise_overflow_error<T>("boost::math::students_t_quantile<%1%>(%1%,%1%)", nullptr, pol);
  426. else
  427. t = sqrt(df * y / x);
  428. //
  429. // Figure out sign based on the size of p:
  430. //
  431. if(p < 0.5)
  432. t = -t;
  433. return t;
  434. }
  435. template <class T, class Policy>
  436. T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const std::true_type*)
  437. {
  438. BOOST_MATH_STD_USING
  439. bool invert = false;
  440. if((df < 2) && (floor(df) != df))
  441. return boost::math::detail::fast_students_t_quantile_imp(df, p, pol, static_cast<std::false_type*>(nullptr));
  442. if(p > 0.5)
  443. {
  444. p = 1 - p;
  445. invert = true;
  446. }
  447. //
  448. // Get an estimate of the result:
  449. //
  450. bool exact;
  451. T t = inverse_students_t(df, p, T(1-p), pol, &exact);
  452. if((t == 0) || exact)
  453. return invert ? -t : t; // can't do better!
  454. //
  455. // Change variables to inverse incomplete beta:
  456. //
  457. T t2 = t * t;
  458. T xb = df / (df + t2);
  459. T y = t2 / (df + t2);
  460. T a = df / 2;
  461. //
  462. // t can be so large that x underflows,
  463. // just return our estimate in that case:
  464. //
  465. if(xb == 0)
  466. return t;
  467. //
  468. // Get incomplete beta and it's derivative:
  469. //
  470. T f1;
  471. T f0 = xb < y ? ibeta_imp(a, constants::half<T>(), xb, pol, false, true, &f1)
  472. : ibeta_imp(constants::half<T>(), a, y, pol, true, true, &f1);
  473. // Get cdf from incomplete beta result:
  474. T p0 = f0 / 2 - p;
  475. // Get pdf from derivative:
  476. T p1 = f1 * sqrt(y * xb * xb * xb / df);
  477. //
  478. // Second derivative divided by p1:
  479. //
  480. // yacas gives:
  481. //
  482. // In> PrettyForm(Simplify(D(t) (1 + t^2/v) ^ (-(v+1)/2)))
  483. //
  484. // | | v + 1 | |
  485. // | -| ----- + 1 | |
  486. // | | 2 | |
  487. // -| | 2 | |
  488. // | | t | |
  489. // | | -- + 1 | |
  490. // | ( v + 1 ) * | v | * t |
  491. // ---------------------------------------------
  492. // v
  493. //
  494. // Which after some manipulation is:
  495. //
  496. // -p1 * t * (df + 1) / (t^2 + df)
  497. //
  498. T p2 = t * (df + 1) / (t * t + df);
  499. // Halley step:
  500. t = fabs(t);
  501. t += p0 / (p1 + p0 * p2 / 2);
  502. return !invert ? -t : t;
  503. }
  504. template <class T, class Policy>
  505. inline T fast_students_t_quantile(T df, T p, const Policy& pol)
  506. {
  507. typedef typename policies::evaluation<T, Policy>::type value_type;
  508. typedef typename policies::normalise<
  509. Policy,
  510. policies::promote_float<false>,
  511. policies::promote_double<false>,
  512. policies::discrete_quantile<>,
  513. policies::assert_undefined<> >::type forwarding_policy;
  514. typedef std::integral_constant<bool,
  515. (std::numeric_limits<T>::digits <= 53)
  516. &&
  517. (std::numeric_limits<T>::is_specialized)
  518. &&
  519. (std::numeric_limits<T>::radix == 2)
  520. > tag_type;
  521. return policies::checked_narrowing_cast<T, forwarding_policy>(fast_students_t_quantile_imp(static_cast<value_type>(df), static_cast<value_type>(p), pol, static_cast<tag_type*>(nullptr)), "boost::math::students_t_quantile<%1%>(%1%,%1%,%1%)");
  522. }
  523. }}} // namespaces
  524. #endif // BOOST_MATH_SF_DETAIL_INV_T_HPP