non_central_t.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,068 行 · 第 1/3 页

HPP
1,068
字号
// boost\math\distributions\non_central_t.hpp// Copyright John Maddock 2008.// Use, modification and distribution are subject to the// Boost Software License, Version 1.0.// (See accompanying file LICENSE_1_0.txt// or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP#define BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP#include <boost/math/distributions/fwd.hpp>#include <boost/math/distributions/non_central_beta.hpp> // for nc beta#include <boost/math/distributions/normal.hpp> // for normal CDF and quantile#include <boost/math/distributions/students_t.hpp>#include <boost/math/distributions/detail/generic_quantile.hpp> // quantilenamespace boost{   namespace math   {      template <class RealType, class Policy>      class non_central_t_distribution;      namespace detail{         template <class T, class Policy>         T non_central_t2_p(T n, T delta, T x, T y, const Policy& pol, T init_val)         {            BOOST_MATH_STD_USING            //            // Variables come first:            //            boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();            T errtol = ldexp(1.0f, -boost::math::policies::digits<T, Policy>());            T d2 = delta * delta / 2;            //            // k is the starting point for iteration, and is the            // maximum of the poisson weighting term:            //            int k = boost::math::itrunc(d2);            // Starting Poisson weight:            T pois = gamma_p_derivative(T(k+1), d2, pol)                * tgamma_delta_ratio(T(k + 1), T(0.5f))               * delta / constants::root_two<T>();            if(pois == 0)               return init_val;            // Starting beta term:            T beta = x < y               ? ibeta(T(k + 1), n / 2, x, pol)               : ibetac(n / 2, T(k + 1), y, pol);            // Recurance term:            T xterm = x < y               ? ibeta_derivative(T(k + 1), n / 2, x, pol)               : ibeta_derivative(n / 2, T(k + 1), y, pol);            xterm *= y / (n / 2 + k);            T poisf(pois), betaf(beta), xtermf(xterm);            T sum = init_val;            if((xterm == 0) && (beta == 0))               return init_val;            //            // Backwards recursion first, this is the stable            // direction for recursion:            //            boost::uintmax_t count = 0;            for(int i = k; i >= 0; --i)            {               T term = beta * pois;               sum += term;               if(fabs(term/sum) < errtol)                  break;               pois *= (i + 0.5f) / d2;               beta += xterm;               xterm *= (i) / (x * (n / 2 + i - 1));               ++count;            }            for(int i = k + 1; ; ++i)            {               poisf *= d2 / (i + 0.5f);               xtermf *= (x * (n / 2 + i - 1)) / (i);               betaf -= xtermf;               T term = poisf * betaf;               sum += term;               if(fabs(term/sum) < errtol)                  break;               ++count;               if(count > max_iter)               {                  return policies::raise_evaluation_error(                     "cdf(non_central_t_distribution<%1%>, %1%)",                      "Series did not converge, closest value was %1%", sum, pol);               }            }            return sum;         }         template <class T, class Policy>         T non_central_t2_q(T n, T delta, T x, T y, const Policy& pol, T init_val)         {            BOOST_MATH_STD_USING            //            // Variables come first:            //            boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();            T errtol = ldexp(1.0f, -boost::math::policies::digits<T, Policy>());            T d2 = delta * delta / 2;            //            // k is the starting point for iteration, and is the            // maximum of the poisson weighting term:            //            int k = boost::math::itrunc(d2);            // Starting Poisson weight:            T pois = gamma_p_derivative(T(k+1), d2, pol)                * tgamma_delta_ratio(T(k + 1), T(0.5f))               * delta / constants::root_two<T>();            if(pois == 0)               return init_val;            // Starting beta term:            T beta = x < y                ? ibetac(T(k + 1), n / 2, x, pol)               : ibeta(n / 2, T(k + 1), y, pol);            // Recurance term:            T xterm = x < y               ? ibeta_derivative(T(k + 1), n / 2, x, pol)               : ibeta_derivative(n / 2, T(k + 1), y, pol);            xterm *= y / (n / 2 + k);            T poisf(pois), betaf(beta), xtermf(xterm);            T sum = init_val;            if((xterm == 0) && (beta == 0))               return init_val;            //            // Forward recursion first, this is the stable direction:            //            boost::uintmax_t count = 0;            for(int i = k + 1; ; ++i)            {               poisf *= d2 / (i + 0.5f);               xtermf *= (x * (n / 2 + i - 1)) / (i);               betaf += xtermf;               T term = poisf * betaf;               sum += term;               if(fabs(term/sum) < errtol)                  break;               if(count > max_iter)               {                  return policies::raise_evaluation_error(                     "cdf(non_central_t_distribution<%1%>, %1%)",                      "Series did not converge, closest value was %1%", sum, pol);               }               ++count;            }            //            // Backwards recursion:            //            for(int i = k; i >= 0; --i)            {               T term = beta * pois;               sum += term;               if(fabs(term/sum) < errtol)                  break;               pois *= (i + 0.5f) / d2;               beta -= xterm;               xterm *= (i) / (x * (n / 2 + i - 1));               ++count;               if(count > max_iter)               {                  return policies::raise_evaluation_error(                     "cdf(non_central_t_distribution<%1%>, %1%)",                      "Series did not converge, closest value was %1%", sum, pol);               }            }            return sum;         }         template <class T, class Policy>         T non_central_t_cdf(T n, T delta, T t, bool invert, const Policy& pol)         {            //            // For t < 0 we have to use reflect:            //            if(t < 0)            {               t = -t;               delta = -delta;               invert = !invert;            }            //            // x and y are the corresponding random            // variables for the noncentral beta distribution,            // with y = 1 - x:            //            T x = t * t / (n + t * t);            T y = n / (n + t * t);            T d2 = delta * delta;            T a = 0.5f;            T b = n / 2;            T c = a + b + d2 / 2;            //            // Crossover point for calculating p or q is the same            // as for the noncentral beta:            //            T cross = 1 - (b / c) * (1 + d2 / (2 * c * c));            T result;            if(x < cross)            {               //               // Calculate p:               //               if(x != 0)               {                  result = non_central_beta_p(a, b, d2, x, y, pol);                  result = non_central_t2_p(n, delta, x, y, pol, result);                  result /= 2;               }               else                  result = 0;               result += cdf(boost::math::normal_distribution<T, Policy>(), -delta);            }            else            {               //               // Calculate q:               //               invert = !invert;               if(x != 0)               {                  result = non_central_beta_q(a, b, d2, x, y, pol);                  result = non_central_t2_q(n, delta, x, y, pol, result);                  result /= 2;               }               else                  result = cdf(complement(boost::math::normal_distribution<T, Policy>(), -delta));            }            if(invert)               result = 1 - result;            return result;         }         template <class T, class Policy>         T non_central_t_quantile(T v, T delta, T p, T q, const Policy&)         {            BOOST_MATH_STD_USING            static const char* function = "quantile(non_central_t_distribution<%1%>, %1%)";            typedef typename policies::evaluation<T, Policy>::type value_type;            typedef typename policies::normalise<               Policy,                policies::promote_float<false>,                policies::promote_double<false>,                policies::discrete_quantile<>,               policies::assert_undefined<> >::type forwarding_policy;               T r;               if(!detail::check_df(                  function,                  v, &r, Policy())                  ||               !detail::check_finite(                  function,                  delta,                  &r,                  Policy())                  ||               !detail::check_probability(                  function,                  p,                  &r,                  Policy()))                     return r;            value_type guess = 0;            if(v > 3)            {               value_type mean = delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f));               value_type var = ((delta * delta + 1) * v) / (v - 2) - mean * mean;               if(p < q)                  guess = quantile(normal_distribution<value_type, forwarding_policy>(mean, var), p);               else                  guess = quantile(complement(normal_distribution<value_type, forwarding_policy>(mean, var), q));            }            //            // We *must* get the sign of the initial guess correct,             // or our root-finder will fail, so double check it now:            //            value_type pzero = non_central_t_cdf(               static_cast<value_type>(v),                static_cast<value_type>(delta),                static_cast<value_type>(0),                !(p < q),                forwarding_policy());            int s;            if(p < q)               s = boost::math::sign(p - pzero);            else               s = boost::math::sign(pzero - q);            if(s != boost::math::sign(guess))            {               guess = s;            }            value_type result = detail::generic_quantile(               non_central_t_distribution<value_type, forwarding_policy>(v, delta),                (p < q ? p : q),                guess,                (p >= q),                function);            return policies::checked_narrowing_cast<T, forwarding_policy>(               result,                function);         }         template <class T, class Policy>         T non_central_t2_pdf(T n, T delta, T x, T y, const Policy& pol, T init_val)         {            BOOST_MATH_STD_USING            //            // Variables come first:            //            boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();            T errtol = ldexp(1.0f, -boost::math::policies::digits<T, Policy>());            T d2 = delta * delta / 2;            //            // k is the starting point for iteration, and is the            // maximum of the poisson weighting term:            //            int k = boost::math::itrunc(d2);            // Starting Poisson weight:            T pois = gamma_p_derivative(T(k+1), d2, pol)                * tgamma_delta_ratio(T(k + 1), T(0.5f))               * delta / constants::root_two<T>();            // Starting beta term:            T xterm = x < y               ? ibeta_derivative(T(k + 1), n / 2, x, pol)               : ibeta_derivative(n / 2, T(k + 1), y, pol);            T poisf(pois), xtermf(xterm);            T sum = init_val;            if((pois == 0) || (xterm == 0))               return init_val;            //            // Backwards recursion first, this is the stable            // direction for recursion:            //            boost::uintmax_t count = 0;            for(int i = k; i >= 0; --i)            {               T term = xterm * pois;               sum += term;               if((fabs(term/sum) < errtol) || (term == 0))                  break;               pois *= (i + 0.5f) / d2;               xterm *= (i) / (x * (n / 2 + i));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?