non_central_t.hpp 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. // boost\math\distributions\non_central_t.hpp
  2. // Copyright John Maddock 2008.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
  8. #define BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
  9. #include <boost/math/distributions/fwd.hpp>
  10. #include <boost/math/distributions/non_central_beta.hpp> // for nc beta
  11. #include <boost/math/distributions/normal.hpp> // for normal CDF and quantile
  12. #include <boost/math/distributions/students_t.hpp>
  13. #include <boost/math/distributions/detail/generic_quantile.hpp> // quantile
  14. #include <boost/math/special_functions/trunc.hpp>
  15. #include <boost/math/special_functions/detail/hypergeometric_series.hpp>
  16. #include <boost/math/quadrature/exp_sinh.hpp>
  17. namespace boost
  18. {
  19. namespace math
  20. {
  21. template <class RealType, class Policy>
  22. class non_central_t_distribution;
  23. namespace detail{
  24. template <class T, class Policy>
  25. T non_central_t2_p(T v, T delta, T x, T y, const Policy& pol, T init_val)
  26. {
  27. BOOST_MATH_STD_USING
  28. //
  29. // Variables come first:
  30. //
  31. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  32. T errtol = policies::get_epsilon<T, Policy>();
  33. T d2 = delta * delta / 2;
  34. //
  35. // k is the starting point for iteration, and is the
  36. // maximum of the poisson weighting term, we don't
  37. // ever allow k == 0 as this can lead to catastrophic
  38. // cancellation errors later (test case is v = 1621286869049072.3
  39. // delta = 0.16212868690490723, x = 0.86987415482475994).
  40. //
  41. long long k = lltrunc(d2);
  42. T pois;
  43. if(k == 0) k = 1;
  44. // Starting Poisson weight:
  45. pois = gamma_p_derivative(T(k+1), d2, pol)
  46. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  47. * delta / constants::root_two<T>();
  48. if(pois == 0)
  49. return init_val;
  50. T xterm, beta;
  51. // Recurrence & starting beta terms:
  52. beta = x < y
  53. ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm)
  54. : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm);
  55. while (fabs(beta * pois) < tools::min_value<T>())
  56. {
  57. if ((k == 0) || (pois == 0))
  58. return init_val;
  59. k /= 2;
  60. pois = gamma_p_derivative(T(k + 1), d2, pol)
  61. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  62. * delta / constants::root_two<T>();
  63. beta = x < y
  64. ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm)
  65. : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm);
  66. }
  67. xterm *= y / (v / 2 + k);
  68. T poisf(pois), betaf(beta), xtermf(xterm);
  69. T sum = init_val;
  70. if((xterm == 0) && (beta == 0))
  71. return init_val;
  72. //
  73. // Backwards recursion first, this is the stable
  74. // direction for recursion:
  75. //
  76. std::uintmax_t count = 0;
  77. T last_term = 0;
  78. for(auto i = k; i >= 0; --i)
  79. {
  80. T term = beta * pois;
  81. sum += term;
  82. // Don't terminate on first term in case we "fixed" k above:
  83. if(((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol) || (v == 2 && i == 0))
  84. break;
  85. last_term = term;
  86. pois *= (i + 0.5f) / d2;
  87. beta += xterm;
  88. xterm *= (i) / (x * (v / 2 + i - 1));
  89. ++count;
  90. }
  91. last_term = 0;
  92. T betaf_lim = betaf * tools::epsilon<T>() * 4;
  93. for(auto i = k + 1; ; ++i)
  94. {
  95. poisf *= d2 / (i + 0.5f);
  96. xtermf *= (x * (v / 2 + i - 1)) / (i);
  97. betaf -= xtermf;
  98. if (betaf < betaf_lim)
  99. break; // Nothing but garbage left in betaf now!!
  100. T term = poisf * betaf;
  101. sum += term;
  102. if((fabs(last_term) >= fabs(term)) && (fabs(term/sum) < errtol))
  103. break;
  104. last_term = term;
  105. ++count;
  106. if(count > max_iter)
  107. {
  108. return policies::raise_evaluation_error("cdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  109. }
  110. }
  111. return sum;
  112. }
  113. template <class T, class Policy>
  114. T non_central_t2_q(T v, T delta, T x, T y, const Policy& pol, T init_val)
  115. {
  116. BOOST_MATH_STD_USING
  117. //
  118. // Variables come first:
  119. //
  120. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  121. T errtol = boost::math::policies::get_epsilon<T, Policy>();
  122. T d2 = delta * delta / 2;
  123. //
  124. // k is the starting point for iteration, and is the
  125. // maximum of the poisson weighting term, we don't allow
  126. // k == 0 as this can cause catastrophic cancellation errors
  127. // (test case is v = 561908036470413.25, delta = 0.056190803647041321,
  128. // x = 1.6155232703966216):
  129. //
  130. long long k = lltrunc(d2);
  131. if(k == 0) k = 1;
  132. // Starting Poisson weight:
  133. T pois;
  134. if((k < static_cast<long long>(max_factorial<T>::value)) && (d2 < tools::log_max_value<T>()) && (log(d2) * k < tools::log_max_value<T>()))
  135. {
  136. //
  137. // For small k we can optimise this calculation by using
  138. // a simpler reduced formula:
  139. //
  140. pois = exp(-d2);
  141. pois *= pow(d2, static_cast<T>(k));
  142. pois /= boost::math::tgamma(T(k + 1 + 0.5), pol);
  143. pois *= delta / constants::root_two<T>();
  144. }
  145. else
  146. {
  147. pois = gamma_p_derivative(T(k+1), d2, pol)
  148. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  149. * delta / constants::root_two<T>();
  150. }
  151. if(pois == 0)
  152. return init_val;
  153. // Recurance term:
  154. T xterm;
  155. T beta;
  156. // Starting beta term:
  157. if(k != 0)
  158. {
  159. beta = x < y
  160. ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, true, true, &xterm)
  161. : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, false, true, &xterm);
  162. xterm *= y / (v / 2 + k);
  163. }
  164. else
  165. {
  166. beta = pow(y, v / 2);
  167. xterm = beta;
  168. }
  169. T poisf(pois), betaf(beta), xtermf(xterm);
  170. T sum = init_val;
  171. if((xterm == 0) && (beta == 0))
  172. return init_val;
  173. //
  174. // Fused forward and backwards recursion:
  175. //
  176. std::uintmax_t count = 0;
  177. T last_term = 0;
  178. for(auto i = k + 1, j = k; ; ++i, --j)
  179. {
  180. poisf *= d2 / (i + 0.5f);
  181. xtermf *= (x * (v / 2 + i - 1)) / (i);
  182. betaf += xtermf;
  183. T term = poisf * betaf;
  184. if(j >= 0)
  185. {
  186. term += beta * pois;
  187. pois *= (j + 0.5f) / d2;
  188. beta -= xterm;
  189. if(!(v == 2 && j == 0))
  190. xterm *= (j) / (x * (v / 2 + j - 1));
  191. }
  192. sum += term;
  193. // Don't terminate on first term in case we "fixed" the value of k above:
  194. if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol)
  195. break;
  196. last_term = term;
  197. if(count > max_iter)
  198. {
  199. return policies::raise_evaluation_error("cdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  200. }
  201. ++count;
  202. }
  203. return sum;
  204. }
  205. template <class T, class Policy>
  206. T non_central_t_cdf(T v, T delta, T t, bool invert, const Policy& pol)
  207. {
  208. BOOST_MATH_STD_USING
  209. if ((boost::math::isinf)(v))
  210. { // Infinite degrees of freedom, so use normal distribution located at delta.
  211. normal_distribution<T, Policy> n(delta, 1);
  212. return cdf(n, t);
  213. }
  214. //
  215. // Otherwise, for t < 0 we have to use the reflection formula:
  216. if(t < 0)
  217. {
  218. t = -t;
  219. delta = -delta;
  220. invert = !invert;
  221. }
  222. if(fabs(delta / (4 * v)) < policies::get_epsilon<T, Policy>())
  223. {
  224. // Approximate with a Student's T centred on delta,
  225. // the crossover point is based on eq 2.6 from
  226. // "A Comparison of Approximations To Percentiles of the
  227. // Noncentral t-Distribution". H. Sahai and M. M. Ojeda,
  228. // Revista Investigacion Operacional Vol 21, No 2, 2000.
  229. // Original sources referenced in the above are:
  230. // "Some Approximations to the Percentage Points of the Noncentral
  231. // t-Distribution". C. van Eeden. International Statistical Review, 29, 4-31.
  232. // "Continuous Univariate Distributions". N.L. Johnson, S. Kotz and
  233. // N. Balkrishnan. 1995. John Wiley and Sons New York.
  234. T result = cdf(students_t_distribution<T, Policy>(v), t - delta);
  235. return invert ? 1 - result : result;
  236. }
  237. //
  238. // x and y are the corresponding random
  239. // variables for the noncentral beta distribution,
  240. // with y = 1 - x:
  241. //
  242. T x = t * t / (v + t * t);
  243. T y = v / (v + t * t);
  244. T d2 = delta * delta;
  245. T a = 0.5f;
  246. T b = v / 2;
  247. T c = a + b + d2 / 2;
  248. //
  249. // Crossover point for calculating p or q is the same
  250. // as for the noncentral beta:
  251. //
  252. T cross = 1 - (b / c) * (1 + d2 / (2 * c * c));
  253. T result;
  254. if(x < cross)
  255. {
  256. //
  257. // Calculate p:
  258. //
  259. if(x != 0)
  260. {
  261. result = non_central_beta_p(a, b, d2, x, y, pol);
  262. result = non_central_t2_p(v, delta, x, y, pol, result);
  263. result /= 2;
  264. }
  265. else
  266. result = 0;
  267. if (invert)
  268. {
  269. result = cdf(complement(boost::math::normal_distribution<T, Policy>(), -delta)) - result;
  270. invert = false;
  271. }
  272. else
  273. result += cdf(boost::math::normal_distribution<T, Policy>(), -delta);
  274. }
  275. else
  276. {
  277. //
  278. // Calculate q:
  279. //
  280. invert = !invert;
  281. if(x != 0)
  282. {
  283. result = non_central_beta_q(a, b, d2, x, y, pol);
  284. result = non_central_t2_q(v, delta, x, y, pol, result);
  285. result /= 2;
  286. }
  287. else // x == 0
  288. result = cdf(complement(boost::math::normal_distribution<T, Policy>(), -delta));
  289. }
  290. if(invert)
  291. result = 1 - result;
  292. return result;
  293. }
  294. template <class T, class Policy>
  295. T non_central_t_quantile(const char* function, T v, T delta, T p, T q, const Policy&)
  296. {
  297. BOOST_MATH_STD_USING
  298. // static const char* function = "quantile(non_central_t_distribution<%1%>, %1%)";
  299. // now passed as function
  300. typedef typename policies::evaluation<T, Policy>::type value_type;
  301. typedef typename policies::normalise<
  302. Policy,
  303. policies::promote_float<false>,
  304. policies::promote_double<false>,
  305. policies::discrete_quantile<>,
  306. policies::assert_undefined<> >::type forwarding_policy;
  307. T r;
  308. if(!detail::check_df_gt0_to_inf(
  309. function,
  310. v, &r, Policy())
  311. ||
  312. !detail::check_non_centrality(
  313. function,
  314. static_cast<T>(delta * delta),
  315. &r,
  316. Policy())
  317. ||
  318. !detail::check_probability(
  319. function,
  320. p,
  321. &r,
  322. Policy()))
  323. return r;
  324. value_type guess = 0;
  325. if ( ((boost::math::isinf)(v)) || (v > 1 / boost::math::tools::epsilon<T>()) )
  326. { // Infinite or very large degrees of freedom, so use normal distribution located at delta.
  327. normal_distribution<T, Policy> n(delta, 1);
  328. if (p < q)
  329. {
  330. return quantile(n, p);
  331. }
  332. else
  333. {
  334. return quantile(complement(n, q));
  335. }
  336. }
  337. else if(v > 3)
  338. { // Use normal distribution to calculate guess.
  339. value_type mean = (v > 1 / policies::get_epsilon<T, Policy>()) ? delta : delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f));
  340. value_type var = (v > 1 / policies::get_epsilon<T, Policy>()) ? value_type(1) : (((delta * delta + 1) * v) / (v - 2) - mean * mean);
  341. if(p < q)
  342. guess = quantile(normal_distribution<value_type, forwarding_policy>(mean, var), p);
  343. else
  344. guess = quantile(complement(normal_distribution<value_type, forwarding_policy>(mean, var), q));
  345. }
  346. //
  347. // We *must* get the sign of the initial guess correct,
  348. // or our root-finder will fail, so double check it now:
  349. //
  350. value_type pzero = non_central_t_cdf(
  351. static_cast<value_type>(v),
  352. static_cast<value_type>(delta),
  353. static_cast<value_type>(0),
  354. !(p < q),
  355. forwarding_policy());
  356. int s;
  357. if(p < q)
  358. s = boost::math::sign(p - pzero);
  359. else
  360. s = boost::math::sign(pzero - q);
  361. if(s != boost::math::sign(guess))
  362. {
  363. guess = static_cast<T>(s);
  364. }
  365. value_type result = detail::generic_quantile(
  366. non_central_t_distribution<value_type, forwarding_policy>(v, delta),
  367. (p < q ? p : q),
  368. guess,
  369. (p >= q),
  370. function);
  371. return policies::checked_narrowing_cast<T, forwarding_policy>(
  372. result,
  373. function);
  374. }
  375. template <class T, class Policy>
  376. T non_central_t_pdf_integral(T x, T v, T mu, const Policy& pol)
  377. {
  378. BOOST_MATH_STD_USING
  379. boost::math::quadrature::exp_sinh<T, Policy> integrator;
  380. T integral = pow(v, v / 2) * exp(-v * mu * mu / (2 * (x * x + v)));
  381. if (integral != 0)
  382. {
  383. integral *= integrator.integrate([&x, v, mu](T y)
  384. {
  385. T p;
  386. if (v * log(y) < tools::log_max_value<T>())
  387. p = pow(y, v) * exp(boost::math::pow<2>((y - mu * x / sqrt(x * x + v))) / -2);
  388. else
  389. p = exp(log(y) * v + boost::math::pow<2>((y - mu * x / sqrt(x * x + v))) / -2);
  390. return p;
  391. });
  392. }
  393. integral /= boost::math::constants::root_pi<T>() * boost::math::tgamma(v / 2, pol) * pow(T(2), (v - 1) / 2) * pow(x * x + v, (v + 1) / 2);
  394. return integral;
  395. }
  396. template <class T, class Policy>
  397. T non_central_t_pdf_hypergeometric(T x, T v, T mu, const Policy& pol)
  398. {
  399. BOOST_MATH_STD_USING
  400. long long scale = 0;
  401. const char* function = "non central T PDF";
  402. //
  403. // We only call this routine when we know that the series form of 1F1 is cheap to evaluate,
  404. // so no need to call the whole 1F1 function, just the series will do:
  405. //
  406. T Av = hypergeometric_1F1_generic_series(static_cast<T>((v + 1) / 2), boost::math::constants::half<T>(), static_cast<T>(mu * mu * x * x / (2 * (x * x + v))), pol, scale, function);
  407. Av = ldexp(Av, static_cast<int>(scale));
  408. scale = 0;
  409. T Bv = hypergeometric_1F1_generic_series(static_cast<T>(v / 2 + T(1)), static_cast<T>(T(3) / 2), static_cast<T>(mu * mu * x * x / (2 * (x * x + v))), pol, scale, function);
  410. Bv = ldexp(Bv, static_cast<int>(scale));
  411. Bv *= boost::math::tgamma_delta_ratio(v / 2 + T(1), -constants::half<T>(), pol);
  412. Bv *= boost::math::constants::root_two<T>() * mu * x / sqrt(x * x + v);
  413. T tolerance = tools::root_epsilon<T>() * Av * 4;
  414. Av += Bv;
  415. if (Av < tolerance)
  416. {
  417. // More than half the digits have cancelled, fall back to the integral method:
  418. return non_central_t_pdf_integral(x, v, mu, pol);
  419. }
  420. Av *= exp(-mu * mu / 2) * pow(1 + x * x / v, -(v + 1) / 2) * boost::math::tgamma_delta_ratio(v / 2 + constants::half<T>(), -constants::half<T>(), pol);
  421. Av /= sqrt(v) * boost::math::constants::root_pi<T>();
  422. return Av;
  423. }
  424. template <class T, class Policy>
  425. T non_central_t2_pdf(T n, T delta, T x, T y, const Policy& pol, T init_val)
  426. {
  427. BOOST_MATH_STD_USING
  428. //
  429. // Variables come first:
  430. //
  431. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  432. T errtol = boost::math::policies::get_epsilon<T, Policy>();
  433. T d2 = delta * delta / 2;
  434. //
  435. // k is the starting point for iteration, and is the
  436. // maximum of the poisson weighting term:
  437. //
  438. long long k = lltrunc(d2);
  439. T pois, xterm;
  440. if(k == 0)
  441. k = 1;
  442. // Starting Poisson weight:
  443. pois = gamma_p_derivative(T(k+1), d2, pol)
  444. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  445. * delta / constants::root_two<T>();
  446. BOOST_MATH_INSTRUMENT_VARIABLE(pois);
  447. // Starting beta term:
  448. xterm = x < y
  449. ? ibeta_derivative(T(k + 1), n / 2, x, pol)
  450. : ibeta_derivative(n / 2, T(k + 1), y, pol);
  451. BOOST_MATH_INSTRUMENT_VARIABLE(xterm);
  452. while (fabs(xterm * pois) < tools::min_value<T>())
  453. {
  454. if (k == 0)
  455. return init_val;
  456. k /= 2;
  457. pois = gamma_p_derivative(T(k + 1), d2, pol)
  458. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  459. * delta / constants::root_two<T>();
  460. BOOST_MATH_INSTRUMENT_VARIABLE(pois);
  461. // Starting beta term:
  462. xterm = x < y
  463. ? ibeta_derivative(T(k + 1), n / 2, x, pol)
  464. : ibeta_derivative(n / 2, T(k + 1), y, pol);
  465. BOOST_MATH_INSTRUMENT_VARIABLE(xterm);
  466. }
  467. T poisf(pois), xtermf(xterm);
  468. T sum = init_val;
  469. //
  470. // Backwards recursion first, this is the stable
  471. // direction for recursion:
  472. //
  473. std::uintmax_t count = 0;
  474. T old_ratio = 1; // arbitrary "large" value
  475. for(auto i = k; i >= 0; --i)
  476. {
  477. T term = xterm * pois;
  478. sum += term;
  479. BOOST_MATH_INSTRUMENT_VARIABLE(sum);
  480. T ratio = fabs(term / sum);
  481. if(((ratio < errtol) && (i != k) && (ratio < old_ratio)) || (term == 0))
  482. break;
  483. old_ratio = ratio;
  484. pois *= (i + 0.5f) / d2;
  485. xterm *= (i) / (x * (n / 2 + i));
  486. ++count;
  487. if(count > max_iter)
  488. {
  489. return policies::raise_evaluation_error("pdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  490. }
  491. }
  492. BOOST_MATH_INSTRUMENT_VARIABLE(sum);
  493. old_ratio = 0;
  494. for(auto i = k + 1; ; ++i)
  495. {
  496. poisf *= d2 / (i + 0.5f);
  497. xtermf *= (x * (n / 2 + i)) / (i);
  498. T term = poisf * xtermf;
  499. sum += term;
  500. T ratio = fabs(term / sum);
  501. if(((ratio < errtol) && (ratio < old_ratio)) || (term == 0))
  502. break;
  503. ++count;
  504. old_ratio = ratio;
  505. if(count > max_iter)
  506. {
  507. return policies::raise_evaluation_error("pdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  508. }
  509. }
  510. BOOST_MATH_INSTRUMENT_VARIABLE(sum);
  511. return sum;
  512. }
  513. template <class T, class Policy>
  514. T non_central_t_pdf(T n, T delta, T t, const Policy& pol)
  515. {
  516. BOOST_MATH_STD_USING
  517. if ((boost::math::isinf)(n))
  518. { // Infinite degrees of freedom, so use normal distribution located at delta.
  519. normal_distribution<T, Policy> norm(delta, 1);
  520. return pdf(norm, t);
  521. }
  522. if(t * t < tools::epsilon<T>())
  523. {
  524. //
  525. // Handle this as a special case, using the formula
  526. // from Weisstein, Eric W.
  527. // "Noncentral Student's t-Distribution."
  528. // From MathWorld--A Wolfram Web Resource.
  529. // http://mathworld.wolfram.com/NoncentralStudentst-Distribution.html
  530. //
  531. // The formula is simplified thanks to the relation
  532. // 1F1(a,b,0) = 1.
  533. //
  534. return tgamma_delta_ratio(n / 2 + 0.5f, T(0.5f))
  535. * sqrt(n / constants::pi<T>())
  536. * exp(-delta * delta / 2) / 2;
  537. }
  538. if(fabs(delta / (4 * n)) < policies::get_epsilon<T, Policy>())
  539. {
  540. // Approximate with a Student's T centred on delta,
  541. // the crossover point is based on eq 2.6 from
  542. // "A Comparison of Approximations To Percentiles of the
  543. // Noncentral t-Distribution". H. Sahai and M. M. Ojeda,
  544. // Revista Investigacion Operacional Vol 21, No 2, 2000.
  545. // Original sources referenced in the above are:
  546. // "Some Approximations to the Percentage Points of the Noncentral
  547. // t-Distribution". C. van Eeden. International Statistical Review, 29, 4-31.
  548. // "Continuous Univariate Distributions". N.L. Johnson, S. Kotz and
  549. // N. Balkrishnan. 1995. John Wiley and Sons New York.
  550. return pdf(students_t_distribution<T, Policy>(n), t - delta);
  551. }
  552. //
  553. // Figure out if the hypergeometric formula will be efficient or not,
  554. // based on where the summit of the series.
  555. //
  556. T a = (n + 1) / 2;
  557. T x = delta * delta * t * t / (2 * (t * t + n));
  558. T summit = (sqrt(x * (4 * a + x)) + x) / 2;
  559. if (summit < 40)
  560. return non_central_t_pdf_hypergeometric(t, n, delta, pol);
  561. //
  562. // Otherwise, for t < 0 we have to use the reflection formula:
  563. //
  564. if (t < 0)
  565. {
  566. t = -t;
  567. delta = -delta;
  568. }
  569. //
  570. // x and y are the corresponding random
  571. // variables for the noncentral beta distribution,
  572. // with y = 1 - x:
  573. //
  574. x = t * t / (n + t * t);
  575. T y = n / (n + t * t);
  576. a = 0.5f;
  577. T b = n / 2;
  578. T d2 = delta * delta;
  579. //
  580. // Calculate pdf:
  581. //
  582. T dt = n * t / (n * n + 2 * n * t * t + t * t * t * t);
  583. BOOST_MATH_INSTRUMENT_VARIABLE(dt);
  584. T result = non_central_beta_pdf(a, b, d2, x, y, pol);
  585. BOOST_MATH_INSTRUMENT_VARIABLE(result);
  586. T tol = tools::root_epsilon<T>() * result;
  587. result = non_central_t2_pdf(n, delta, x, y, pol, result);
  588. BOOST_MATH_INSTRUMENT_VARIABLE(result);
  589. result *= dt;
  590. if (result <= tol)
  591. {
  592. // More than half the digits in the result have cancelled,
  593. // Try direct integration... super slow but reliable as far as we can tell...
  594. if (delta < 0)
  595. {
  596. // reflect back:
  597. delta = -delta;
  598. t = -t;
  599. }
  600. result = non_central_t_pdf_integral(t, n, delta, pol);
  601. }
  602. return result;
  603. }
  604. template <class T, class Policy>
  605. T mean(T v, T delta, const Policy& pol)
  606. {
  607. if ((boost::math::isinf)(v))
  608. {
  609. return delta;
  610. }
  611. BOOST_MATH_STD_USING
  612. if (v > 1 / boost::math::tools::epsilon<T>() )
  613. {
  614. //normal_distribution<T, Policy> n(delta, 1);
  615. //return boost::math::mean(n);
  616. return delta;
  617. }
  618. else
  619. {
  620. return delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f), pol);
  621. }
  622. // Other moments use mean so using normal distribution is propagated.
  623. }
  624. template <class T, class Policy>
  625. T variance(T v, T delta, const Policy& pol)
  626. {
  627. if ((boost::math::isinf)(v))
  628. {
  629. return 1;
  630. }
  631. if (delta == 0)
  632. { // == Student's t
  633. return v / (v - 2);
  634. }
  635. T result = ((delta * delta + 1) * v) / (v - 2);
  636. T m = mean(v, delta, pol);
  637. result -= m * m;
  638. return result;
  639. }
  640. template <class T, class Policy>
  641. T skewness(T v, T delta, const Policy& pol)
  642. {
  643. BOOST_MATH_STD_USING
  644. if ((boost::math::isinf)(v))
  645. {
  646. return 0;
  647. }
  648. if(delta == 0)
  649. { // == Student's t
  650. return 0;
  651. }
  652. T mean = boost::math::detail::mean(v, delta, pol);
  653. T l2 = delta * delta;
  654. T var = ((l2 + 1) * v) / (v - 2) - mean * mean;
  655. T result = -2 * var;
  656. result += v * (l2 + 2 * v - 3) / ((v - 3) * (v - 2));
  657. result *= mean;
  658. result /= pow(var, T(1.5f));
  659. return result;
  660. }
  661. template <class T, class Policy>
  662. T kurtosis_excess(T v, T delta, const Policy& pol)
  663. {
  664. BOOST_MATH_STD_USING
  665. if ((boost::math::isinf)(v))
  666. {
  667. return 1;
  668. }
  669. if (delta == 0)
  670. { // == Student's t
  671. return 1;
  672. }
  673. T mean = boost::math::detail::mean(v, delta, pol);
  674. T l2 = delta * delta;
  675. T var = ((l2 + 1) * v) / (v - 2) - mean * mean;
  676. T result = -3 * var;
  677. result += v * (l2 * (v + 1) + 3 * (3 * v - 5)) / ((v - 3) * (v - 2));
  678. result *= -mean * mean;
  679. result += v * v * (l2 * l2 + 6 * l2 + 3) / ((v - 4) * (v - 2));
  680. result /= var * var;
  681. result -= static_cast<T>(3);
  682. return result;
  683. }
  684. #if 0
  685. //
  686. // This code is disabled, since there can be multiple answers to the
  687. // question, and it's not clear how to find the "right" one.
  688. //
  689. template <class RealType, class Policy>
  690. struct t_degrees_of_freedom_finder
  691. {
  692. t_degrees_of_freedom_finder(
  693. RealType delta_, RealType x_, RealType p_, bool c)
  694. : delta(delta_), x(x_), p(p_), comp(c) {}
  695. RealType operator()(const RealType& v)
  696. {
  697. non_central_t_distribution<RealType, Policy> d(v, delta);
  698. return comp ?
  699. p - cdf(complement(d, x))
  700. : cdf(d, x) - p;
  701. }
  702. private:
  703. RealType delta;
  704. RealType x;
  705. RealType p;
  706. bool comp;
  707. };
  708. template <class RealType, class Policy>
  709. inline RealType find_t_degrees_of_freedom(
  710. RealType delta, RealType x, RealType p, RealType q, const Policy& pol)
  711. {
  712. const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
  713. if((p == 0) || (q == 0))
  714. {
  715. //
  716. // Can't a thing if one of p and q is zero:
  717. //
  718. return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", // LCOV_EXCL_LINE
  719. RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
  720. }
  721. t_degrees_of_freedom_finder<RealType, Policy> f(delta, x, p < q ? p : q, p < q ? false : true);
  722. tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
  723. std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  724. //
  725. // Pick an initial guess:
  726. //
  727. RealType guess = 200;
  728. std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
  729. f, guess, RealType(2), false, tol, max_iter, pol);
  730. RealType result = ir.first + (ir.second - ir.first) / 2;
  731. if(max_iter >= policies::get_max_root_iterations<Policy>())
  732. {
  733. return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
  734. " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
  735. }
  736. return result;
  737. }
  738. template <class RealType, class Policy>
  739. struct t_non_centrality_finder
  740. {
  741. t_non_centrality_finder(
  742. RealType v_, RealType x_, RealType p_, bool c)
  743. : v(v_), x(x_), p(p_), comp(c) {}
  744. RealType operator()(const RealType& delta)
  745. {
  746. non_central_t_distribution<RealType, Policy> d(v, delta);
  747. return comp ?
  748. p - cdf(complement(d, x))
  749. : cdf(d, x) - p;
  750. }
  751. private:
  752. RealType v;
  753. RealType x;
  754. RealType p;
  755. bool comp;
  756. };
  757. template <class RealType, class Policy>
  758. inline RealType find_t_non_centrality(
  759. RealType v, RealType x, RealType p, RealType q, const Policy& pol)
  760. {
  761. const char* function = "non_central_t<%1%>::find_t_non_centrality";
  762. if((p == 0) || (q == 0))
  763. {
  764. //
  765. // Can't do a thing if one of p and q is zero:
  766. //
  767. return policies::raise_evaluation_error<RealType>(function, "Can't find non-centrality parameter when the probability is 0 or 1, only possible answer is %1%", // LCOV_EXCL_LINE
  768. RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
  769. }
  770. t_non_centrality_finder<RealType, Policy> f(v, x, p < q ? p : q, p < q ? false : true);
  771. tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
  772. std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  773. //
  774. // Pick an initial guess that we know is the right side of
  775. // zero:
  776. //
  777. RealType guess;
  778. if(f(0) < 0)
  779. guess = 1;
  780. else
  781. guess = -1;
  782. std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
  783. f, guess, RealType(2), false, tol, max_iter, pol);
  784. RealType result = ir.first + (ir.second - ir.first) / 2;
  785. if(max_iter >= policies::get_max_root_iterations<Policy>())
  786. {
  787. return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
  788. " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
  789. }
  790. return result;
  791. }
  792. #endif
  793. } // namespace detail ======================================================================
  794. template <class RealType = double, class Policy = policies::policy<> >
  795. class non_central_t_distribution
  796. {
  797. public:
  798. typedef RealType value_type;
  799. typedef Policy policy_type;
  800. non_central_t_distribution(RealType v_, RealType lambda) : v(v_), ncp(lambda)
  801. {
  802. const char* function = "boost::math::non_central_t_distribution<%1%>::non_central_t_distribution(%1%,%1%)";
  803. RealType r;
  804. detail::check_df_gt0_to_inf(
  805. function,
  806. v, &r, Policy());
  807. detail::check_non_centrality(
  808. function,
  809. static_cast<value_type>(lambda * lambda),
  810. &r,
  811. Policy());
  812. } // non_central_t_distribution constructor.
  813. RealType degrees_of_freedom() const
  814. { // Private data getter function.
  815. return v;
  816. }
  817. RealType non_centrality() const
  818. { // Private data getter function.
  819. return ncp;
  820. }
  821. #if 0
  822. //
  823. // This code is disabled, since there can be multiple answers to the
  824. // question, and it's not clear how to find the "right" one.
  825. //
  826. static RealType find_degrees_of_freedom(RealType delta, RealType x, RealType p)
  827. {
  828. const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
  829. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  830. typedef typename policies::normalise<
  831. Policy,
  832. policies::promote_float<false>,
  833. policies::promote_double<false>,
  834. policies::discrete_quantile<>,
  835. policies::assert_undefined<> >::type forwarding_policy;
  836. value_type result = detail::find_t_degrees_of_freedom(
  837. static_cast<value_type>(delta),
  838. static_cast<value_type>(x),
  839. static_cast<value_type>(p),
  840. static_cast<value_type>(1-p),
  841. forwarding_policy());
  842. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  843. result,
  844. function);
  845. }
  846. template <class A, class B, class C>
  847. static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
  848. {
  849. const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
  850. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  851. typedef typename policies::normalise<
  852. Policy,
  853. policies::promote_float<false>,
  854. policies::promote_double<false>,
  855. policies::discrete_quantile<>,
  856. policies::assert_undefined<> >::type forwarding_policy;
  857. value_type result = detail::find_t_degrees_of_freedom(
  858. static_cast<value_type>(c.dist),
  859. static_cast<value_type>(c.param1),
  860. static_cast<value_type>(1-c.param2),
  861. static_cast<value_type>(c.param2),
  862. forwarding_policy());
  863. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  864. result,
  865. function);
  866. }
  867. static RealType find_non_centrality(RealType v, RealType x, RealType p)
  868. {
  869. const char* function = "non_central_t<%1%>::find_t_non_centrality";
  870. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  871. typedef typename policies::normalise<
  872. Policy,
  873. policies::promote_float<false>,
  874. policies::promote_double<false>,
  875. policies::discrete_quantile<>,
  876. policies::assert_undefined<> >::type forwarding_policy;
  877. value_type result = detail::find_t_non_centrality(
  878. static_cast<value_type>(v),
  879. static_cast<value_type>(x),
  880. static_cast<value_type>(p),
  881. static_cast<value_type>(1-p),
  882. forwarding_policy());
  883. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  884. result,
  885. function);
  886. }
  887. template <class A, class B, class C>
  888. static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
  889. {
  890. const char* function = "non_central_t<%1%>::find_t_non_centrality";
  891. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  892. typedef typename policies::normalise<
  893. Policy,
  894. policies::promote_float<false>,
  895. policies::promote_double<false>,
  896. policies::discrete_quantile<>,
  897. policies::assert_undefined<> >::type forwarding_policy;
  898. value_type result = detail::find_t_non_centrality(
  899. static_cast<value_type>(c.dist),
  900. static_cast<value_type>(c.param1),
  901. static_cast<value_type>(1-c.param2),
  902. static_cast<value_type>(c.param2),
  903. forwarding_policy());
  904. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  905. result,
  906. function);
  907. }
  908. #endif
  909. private:
  910. // Data member, initialized by constructor.
  911. RealType v; // degrees of freedom
  912. RealType ncp; // non-centrality parameter
  913. }; // template <class RealType, class Policy> class non_central_t_distribution
  914. typedef non_central_t_distribution<double> non_central_t; // Reserved name of type double.
  915. #ifdef __cpp_deduction_guides
  916. template <class RealType>
  917. non_central_t_distribution(RealType,RealType)->non_central_t_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  918. #endif
  919. // Non-member functions to give properties of the distribution.
  920. template <class RealType, class Policy>
  921. inline const std::pair<RealType, RealType> range(const non_central_t_distribution<RealType, Policy>& /* dist */)
  922. { // Range of permissible values for random variable k.
  923. using boost::math::tools::max_value;
  924. return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
  925. }
  926. template <class RealType, class Policy>
  927. inline const std::pair<RealType, RealType> support(const non_central_t_distribution<RealType, Policy>& /* dist */)
  928. { // Range of supported values for random variable k.
  929. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  930. using boost::math::tools::max_value;
  931. return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
  932. }
  933. template <class RealType, class Policy>
  934. inline RealType mode(const non_central_t_distribution<RealType, Policy>& dist)
  935. { // mode.
  936. static const char* function = "mode(non_central_t_distribution<%1%> const&)";
  937. RealType v = dist.degrees_of_freedom();
  938. RealType l = dist.non_centrality();
  939. RealType r;
  940. if(!detail::check_df_gt0_to_inf(
  941. function,
  942. v, &r, Policy())
  943. ||
  944. !detail::check_non_centrality(
  945. function,
  946. static_cast<RealType>(l * l),
  947. &r,
  948. Policy()))
  949. return static_cast<RealType>(r);
  950. BOOST_MATH_STD_USING
  951. RealType m = v < 3 ? 0 : detail::mean(v, l, Policy());
  952. RealType var = v < 4 ? 1 : detail::variance(v, l, Policy());
  953. return detail::generic_find_mode(
  954. dist,
  955. m,
  956. function,
  957. sqrt(var));
  958. }
  959. template <class RealType, class Policy>
  960. inline RealType mean(const non_central_t_distribution<RealType, Policy>& dist)
  961. {
  962. BOOST_MATH_STD_USING
  963. const char* function = "mean(const non_central_t_distribution<%1%>&)";
  964. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  965. typedef typename policies::normalise<
  966. Policy,
  967. policies::promote_float<false>,
  968. policies::promote_double<false>,
  969. policies::discrete_quantile<>,
  970. policies::assert_undefined<> >::type forwarding_policy;
  971. RealType v = dist.degrees_of_freedom();
  972. RealType l = dist.non_centrality();
  973. RealType r;
  974. if(!detail::check_df_gt0_to_inf(
  975. function,
  976. v, &r, Policy())
  977. ||
  978. !detail::check_non_centrality(
  979. function,
  980. static_cast<RealType>(l * l),
  981. &r,
  982. Policy()))
  983. return static_cast<RealType>(r);
  984. if(v <= 1)
  985. return policies::raise_domain_error<RealType>(
  986. function,
  987. "The non-central t distribution has no defined mean for degrees of freedom <= 1: got v=%1%.", v, Policy());
  988. // return l * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, RealType(0.5f));
  989. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  990. detail::mean(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  991. } // mean
  992. template <class RealType, class Policy>
  993. inline RealType variance(const non_central_t_distribution<RealType, Policy>& dist)
  994. { // variance.
  995. const char* function = "variance(const non_central_t_distribution<%1%>&)";
  996. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  997. typedef typename policies::normalise<
  998. Policy,
  999. policies::promote_float<false>,
  1000. policies::promote_double<false>,
  1001. policies::discrete_quantile<>,
  1002. policies::assert_undefined<> >::type forwarding_policy;
  1003. BOOST_MATH_STD_USING
  1004. RealType v = dist.degrees_of_freedom();
  1005. RealType l = dist.non_centrality();
  1006. RealType r;
  1007. if(!detail::check_df_gt0_to_inf(
  1008. function,
  1009. v, &r, Policy())
  1010. ||
  1011. !detail::check_non_centrality(
  1012. function,
  1013. static_cast<RealType>(l * l),
  1014. &r,
  1015. Policy()))
  1016. return static_cast<RealType>(r);
  1017. if(v <= 2)
  1018. return policies::raise_domain_error<RealType>(
  1019. function,
  1020. "The non-central t distribution has no defined variance for degrees of freedom <= 2: got v=%1%.", v, Policy());
  1021. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1022. detail::variance(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  1023. }
  1024. // RealType standard_deviation(const non_central_t_distribution<RealType, Policy>& dist)
  1025. // standard_deviation provided by derived accessors.
  1026. template <class RealType, class Policy>
  1027. inline RealType skewness(const non_central_t_distribution<RealType, Policy>& dist)
  1028. { // skewness = sqrt(l).
  1029. const char* function = "skewness(const non_central_t_distribution<%1%>&)";
  1030. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1031. typedef typename policies::normalise<
  1032. Policy,
  1033. policies::promote_float<false>,
  1034. policies::promote_double<false>,
  1035. policies::discrete_quantile<>,
  1036. policies::assert_undefined<> >::type forwarding_policy;
  1037. RealType v = dist.degrees_of_freedom();
  1038. RealType l = dist.non_centrality();
  1039. RealType r;
  1040. if(!detail::check_df_gt0_to_inf(
  1041. function,
  1042. v, &r, Policy())
  1043. ||
  1044. !detail::check_non_centrality(
  1045. function,
  1046. static_cast<RealType>(l * l),
  1047. &r,
  1048. Policy()))
  1049. return static_cast<RealType>(r);
  1050. if(v <= 3)
  1051. return policies::raise_domain_error<RealType>(
  1052. function,
  1053. "The non-central t distribution has no defined skewness for degrees of freedom <= 3: got v=%1%.", v, Policy());;
  1054. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1055. detail::skewness(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  1056. }
  1057. template <class RealType, class Policy>
  1058. inline RealType kurtosis_excess(const non_central_t_distribution<RealType, Policy>& dist)
  1059. {
  1060. const char* function = "kurtosis_excess(const non_central_t_distribution<%1%>&)";
  1061. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1062. typedef typename policies::normalise<
  1063. Policy,
  1064. policies::promote_float<false>,
  1065. policies::promote_double<false>,
  1066. policies::discrete_quantile<>,
  1067. policies::assert_undefined<> >::type forwarding_policy;
  1068. RealType v = dist.degrees_of_freedom();
  1069. RealType l = dist.non_centrality();
  1070. RealType r;
  1071. if(!detail::check_df_gt0_to_inf(
  1072. function,
  1073. v, &r, Policy())
  1074. ||
  1075. !detail::check_non_centrality(
  1076. function,
  1077. static_cast<RealType>(l * l),
  1078. &r,
  1079. Policy()))
  1080. return static_cast<RealType>(r);
  1081. if(v <= 4)
  1082. return policies::raise_domain_error<RealType>(
  1083. function,
  1084. "The non-central t distribution has no defined kurtosis for degrees of freedom <= 4: got v=%1%.", v, Policy());;
  1085. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1086. detail::kurtosis_excess(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  1087. } // kurtosis_excess
  1088. template <class RealType, class Policy>
  1089. inline RealType kurtosis(const non_central_t_distribution<RealType, Policy>& dist)
  1090. {
  1091. return kurtosis_excess(dist) + 3;
  1092. }
  1093. template <class RealType, class Policy>
  1094. inline RealType pdf(const non_central_t_distribution<RealType, Policy>& dist, const RealType& t)
  1095. { // Probability Density/Mass Function.
  1096. const char* function = "pdf(non_central_t_distribution<%1%>, %1%)";
  1097. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1098. typedef typename policies::normalise<
  1099. Policy,
  1100. policies::promote_float<false>,
  1101. policies::promote_double<false>,
  1102. policies::discrete_quantile<>,
  1103. policies::assert_undefined<> >::type forwarding_policy;
  1104. RealType v = dist.degrees_of_freedom();
  1105. RealType l = dist.non_centrality();
  1106. RealType r;
  1107. if(!detail::check_df_gt0_to_inf(
  1108. function,
  1109. v, &r, Policy())
  1110. ||
  1111. !detail::check_non_centrality(
  1112. function,
  1113. static_cast<RealType>(l * l), // we need l^2 to be countable.
  1114. &r,
  1115. Policy())
  1116. ||
  1117. !detail::check_x(
  1118. function,
  1119. t,
  1120. &r,
  1121. Policy()))
  1122. return static_cast<RealType>(r);
  1123. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1124. detail::non_central_t_pdf(static_cast<value_type>(v),
  1125. static_cast<value_type>(l),
  1126. static_cast<value_type>(t),
  1127. Policy()),
  1128. function);
  1129. } // pdf
  1130. template <class RealType, class Policy>
  1131. RealType cdf(const non_central_t_distribution<RealType, Policy>& dist, const RealType& x)
  1132. {
  1133. const char* function = "boost::math::cdf(non_central_t_distribution<%1%>&, %1%)";
  1134. // was const char* function = "boost::math::non_central_t_distribution<%1%>::cdf(%1%)";
  1135. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1136. typedef typename policies::normalise<
  1137. Policy,
  1138. policies::promote_float<false>,
  1139. policies::promote_double<false>,
  1140. policies::discrete_quantile<>,
  1141. policies::assert_undefined<> >::type forwarding_policy;
  1142. RealType v = dist.degrees_of_freedom();
  1143. RealType l = dist.non_centrality();
  1144. RealType r;
  1145. if(!detail::check_df_gt0_to_inf(
  1146. function,
  1147. v, &r, Policy())
  1148. ||
  1149. !detail::check_non_centrality(
  1150. function,
  1151. static_cast<RealType>(l * l),
  1152. &r,
  1153. Policy())
  1154. ||
  1155. !detail::check_x(
  1156. function,
  1157. x,
  1158. &r,
  1159. Policy()))
  1160. return static_cast<RealType>(r);
  1161. if ((boost::math::isinf)(v))
  1162. { // Infinite degrees of freedom, so use normal distribution located at delta.
  1163. normal_distribution<RealType, Policy> n(l, 1);
  1164. cdf(n, x);
  1165. //return cdf(normal_distribution<RealType, Policy>(l, 1), x);
  1166. }
  1167. if(l == 0)
  1168. { // NO non-centrality, so use Student's t instead.
  1169. return cdf(students_t_distribution<RealType, Policy>(v), x);
  1170. }
  1171. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1172. detail::non_central_t_cdf(
  1173. static_cast<value_type>(v),
  1174. static_cast<value_type>(l),
  1175. static_cast<value_type>(x),
  1176. false, Policy()),
  1177. function);
  1178. } // cdf
  1179. template <class RealType, class Policy>
  1180. RealType cdf(const complemented2_type<non_central_t_distribution<RealType, Policy>, RealType>& c)
  1181. { // Complemented Cumulative Distribution Function
  1182. // was const char* function = "boost::math::non_central_t_distribution<%1%>::cdf(%1%)";
  1183. const char* function = "boost::math::cdf(const complement(non_central_t_distribution<%1%>&), %1%)";
  1184. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1185. typedef typename policies::normalise<
  1186. Policy,
  1187. policies::promote_float<false>,
  1188. policies::promote_double<false>,
  1189. policies::discrete_quantile<>,
  1190. policies::assert_undefined<> >::type forwarding_policy;
  1191. non_central_t_distribution<RealType, Policy> const& dist = c.dist;
  1192. RealType x = c.param;
  1193. RealType v = dist.degrees_of_freedom();
  1194. RealType l = dist.non_centrality(); // aka delta
  1195. RealType r;
  1196. if(!detail::check_df_gt0_to_inf(
  1197. function,
  1198. v, &r, Policy())
  1199. ||
  1200. !detail::check_non_centrality(
  1201. function,
  1202. static_cast<RealType>(l * l),
  1203. &r,
  1204. Policy())
  1205. ||
  1206. !detail::check_x(
  1207. function,
  1208. x,
  1209. &r,
  1210. Policy()))
  1211. return static_cast<RealType>(r);
  1212. if ((boost::math::isinf)(v))
  1213. { // Infinite degrees of freedom, so use normal distribution located at delta.
  1214. normal_distribution<RealType, Policy> n(l, 1);
  1215. return cdf(complement(n, x));
  1216. }
  1217. if(l == 0)
  1218. { // zero non-centrality so use Student's t distribution.
  1219. return cdf(complement(students_t_distribution<RealType, Policy>(v), x));
  1220. }
  1221. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1222. detail::non_central_t_cdf(
  1223. static_cast<value_type>(v),
  1224. static_cast<value_type>(l),
  1225. static_cast<value_type>(x),
  1226. true, Policy()),
  1227. function);
  1228. } // ccdf
  1229. template <class RealType, class Policy>
  1230. inline RealType quantile(const non_central_t_distribution<RealType, Policy>& dist, const RealType& p)
  1231. { // Quantile (or Percent Point) function.
  1232. static const char* function = "quantile(const non_central_t_distribution<%1%>, %1%)";
  1233. RealType v = dist.degrees_of_freedom();
  1234. RealType l = dist.non_centrality();
  1235. return detail::non_central_t_quantile(function, v, l, p, RealType(1-p), Policy());
  1236. } // quantile
  1237. template <class RealType, class Policy>
  1238. inline RealType quantile(const complemented2_type<non_central_t_distribution<RealType, Policy>, RealType>& c)
  1239. { // Quantile (or Percent Point) function.
  1240. static const char* function = "quantile(const complement(non_central_t_distribution<%1%>, %1%))";
  1241. non_central_t_distribution<RealType, Policy> const& dist = c.dist;
  1242. RealType q = c.param;
  1243. RealType v = dist.degrees_of_freedom();
  1244. RealType l = dist.non_centrality();
  1245. return detail::non_central_t_quantile(function, v, l, RealType(1-q), q, Policy());
  1246. } // quantile complement.
  1247. } // namespace math
  1248. } // namespace boost
  1249. // This include must be at the end, *after* the accessors
  1250. // for this distribution have been defined, in order to
  1251. // keep compilers that support two-phase lookup happy.
  1252. #include <boost/math/distributions/detail/derived_accessors.hpp>
  1253. #endif // BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP