T non_central_t2_q(T v, 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 = boost::math::policies::get_epsilon<T, Policy>(); T d2 = delta * delta / 2; // // k is the starting point for iteration, and is the // maximum of the poisson weighting term, we don't allow // k == 0 as this can cause catastrophic cancellation errors // (test case is v = 561908036470413.25, delta = 0.056190803647041321, // x = 1.6155232703966216): // int k = itrunc(d2); if(k == 0) k = 1; // Starting Poisson weight: T pois; if((k < (int)(max_factorial<T>::value)) && (d2 < tools::log_max_value<T>()) && (log(d2) * k < tools::log_max_value<T>())) { // // For small k we can optimise this calculation by using // a simpler reduced formula: // pois = exp(-d2); pois *= pow(d2, static_cast<T>(k)); pois /= boost::math::tgamma(T(k + 1 + 0.5), pol); pois *= delta / constants::root_two<T>(); } else { 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; // Recurance term: T xterm; T beta; // Starting beta term: if(k != 0) { beta = x < y ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, true, true, &xterm) : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, false, true, &xterm); xterm *= y / (v / 2 + k); } else { beta = pow(y, v / 2); xterm = beta; } T poisf(pois), betaf(beta), xtermf(xterm); T sum = init_val; if((xterm == 0) && (beta == 0)) return init_val; // // Fused forward and backwards recursion: // boost::uintmax_t count = 0; T last_term = 0; for(int i = k + 1, j = k; ; ++i, --j) { poisf *= d2 / (i + 0.5f); xtermf *= (x * (v / 2 + i - 1)) / (i); betaf += xtermf; T term = poisf * betaf; if(j >= 0) { term += beta * pois; pois *= (j + 0.5f) / d2; beta -= xterm; xterm *= (j) / (x * (v / 2 + j - 1)); } sum += term; // Don't terminate on first term in case we "fixed" the value of k above: if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol) break; last_term = term; 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; } return sum; }
T non_central_t2_p(T v, 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 = policies::get_epsilon<T, Policy>(); T d2 = delta * delta / 2; // // k is the starting point for iteration, and is the // maximum of the poisson weighting term, we don't // ever allow k == 0 as this can lead to catastrophic // cancellation errors later (test case is v = 1621286869049072.3 // delta = 0.16212868690490723, x = 0.86987415482475994). // int k = itrunc(d2); T pois; if(k == 0) k = 1; // Starting Poisson weight: 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; T xterm, beta; // Recurrance & starting beta terms: beta = x < y ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm) : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm); xterm *= y / (v / 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; T last_term = 0; for(int i = k; i >= 0; --i) { T term = beta * pois; sum += term; // Don't terminate on first term in case we "fixed" k above: if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol) break; last_term = term; pois *= (i + 0.5f) / d2; beta += xterm; xterm *= (i) / (x * (v / 2 + i - 1)); ++count; } last_term = 0; for(int i = k + 1; ; ++i) { poisf *= d2 / (i + 0.5f); xtermf *= (x * (v / 2 + i - 1)) / (i); betaf -= xtermf; T term = poisf * betaf; sum += term; if((fabs(last_term) > fabs(term)) && (fabs(term/sum) < errtol)) break; last_term = term; ++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; }
int test_main(int, char* []) { int i; TEST_POLICY_SF(tgamma(3.0)); TEST_POLICY_SF(tgamma1pm1(0.25)); TEST_POLICY_SF(lgamma(50.0)); TEST_POLICY_SF(lgamma(50.0, &i)); TEST_POLICY_SF(digamma(12.0)); TEST_POLICY_SF(tgamma_ratio(12.0, 13.5)); TEST_POLICY_SF(tgamma_delta_ratio(100.0, 0.25)); TEST_POLICY_SF(factorial<double>(8)); TEST_POLICY_SF(unchecked_factorial<double>(3)); TEST_POLICY_SF(double_factorial<double>(5)); TEST_POLICY_SF(rising_factorial(20.5, 5)); TEST_POLICY_SF(falling_factorial(10.2, 7)); TEST_POLICY_SF(tgamma(12.0, 13.0)); TEST_POLICY_SF(tgamma_lower(12.0, 13.0)); TEST_POLICY_SF(gamma_p(12.0, 13.0)); TEST_POLICY_SF(gamma_q(12.0, 15.0)); TEST_POLICY_SF(gamma_p_inv(12.0, 0.25)); TEST_POLICY_SF(gamma_q_inv(15.0, 0.25)); TEST_POLICY_SF(gamma_p_inva(12.0, 0.25)); TEST_POLICY_SF(gamma_q_inva(12.0, 0.25)); TEST_POLICY_SF(erf(2.5)); TEST_POLICY_SF(erfc(2.5)); TEST_POLICY_SF(erf_inv(0.25)); TEST_POLICY_SF(erfc_inv(0.25)); TEST_POLICY_SF(beta(12.0, 15.0)); TEST_POLICY_SF(beta(12.0, 15.0, 0.25)); TEST_POLICY_SF(betac(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibeta(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibetac(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibeta_inv(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibetac_inv(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibeta_inva(12.0, 0.75, 0.25)); TEST_POLICY_SF(ibetac_inva(12.0, 0.75, 0.25)); TEST_POLICY_SF(ibeta_invb(12.0, 0.75, 0.25)); TEST_POLICY_SF(ibetac_invb(12.0, 0.75, 0.25)); TEST_POLICY_SF(gamma_p_derivative(12.0, 15.0)); TEST_POLICY_SF(ibeta_derivative(12.0, 15.75, 0.25)); TEST_POLICY_SF(fpclassify(12.0)); TEST_POLICY_SF(isfinite(12.0)); TEST_POLICY_SF(isnormal(12.0)); TEST_POLICY_SF(isnan(12.0)); TEST_POLICY_SF(isinf(12.0)); TEST_POLICY_SF(log1p(0.0025)); TEST_POLICY_SF(expm1(0.0025)); TEST_POLICY_SF(cbrt(30.0)); TEST_POLICY_SF(sqrt1pm1(0.0025)); TEST_POLICY_SF(powm1(1.0025, 12.0)); TEST_POLICY_SF(legendre_p(5, 0.75)); TEST_POLICY_SF(legendre_p(7, 3, 0.75)); TEST_POLICY_SF(legendre_q(5, 0.75)); TEST_POLICY_SF(legendre_next(2, 0.25, 12.0, 5.0)); TEST_POLICY_SF(legendre_next(2, 2, 0.25, 12.0, 5.0)); TEST_POLICY_SF(laguerre(5, 12.2)); TEST_POLICY_SF(laguerre(7, 3, 5.0)); TEST_POLICY_SF(laguerre_next(2, 5.0, 12.0, 5.0)); TEST_POLICY_SF(laguerre_next(5, 3, 5.0, 20.0, 10.0)); TEST_POLICY_SF(hermite(1, 2.0)); TEST_POLICY_SF(hermite_next(2, 2.0, 3.0, 2.0)); TEST_POLICY_SF(spherical_harmonic_r(5, 4, 0.75, 0.25)); TEST_POLICY_SF(spherical_harmonic_i(5, 4, 0.75, 0.25)); TEST_POLICY_SF(ellint_1(0.25)); TEST_POLICY_SF(ellint_1(0.25, 0.75)); TEST_POLICY_SF(ellint_2(0.25)); TEST_POLICY_SF(ellint_2(0.25, 0.75)); TEST_POLICY_SF(ellint_3(0.25, 0.75)); TEST_POLICY_SF(ellint_3(0.25, 0.125, 0.75)); TEST_POLICY_SF(ellint_rc(3.0, 5.0)); TEST_POLICY_SF(ellint_rd(2.0, 3.0, 4.0)); TEST_POLICY_SF(ellint_rf(2.0, 3.0, 4.0)); TEST_POLICY_SF(ellint_rj(2.0, 3.0, 5.0, 0.25)); TEST_POLICY_SF(hypot(5.0, 3.0)); TEST_POLICY_SF(sinc_pi(3.0)); TEST_POLICY_SF(sinhc_pi(2.0)); TEST_POLICY_SF(asinh(12.0)); TEST_POLICY_SF(acosh(5.0)); TEST_POLICY_SF(atanh(0.75)); TEST_POLICY_SF(sin_pi(5.0)); TEST_POLICY_SF(cos_pi(6.0)); TEST_POLICY_SF(cyl_neumann(2.0, 5.0)); TEST_POLICY_SF(cyl_neumann(2, 5.0)); TEST_POLICY_SF(cyl_bessel_j(2.0, 5.0)); TEST_POLICY_SF(cyl_bessel_j(2, 5.0)); TEST_POLICY_SF(cyl_bessel_i(3.0, 5.0)); TEST_POLICY_SF(cyl_bessel_i(3, 5.0)); TEST_POLICY_SF(cyl_bessel_k(3.0, 5.0)); TEST_POLICY_SF(cyl_bessel_k(3, 5.0)); TEST_POLICY_SF(sph_bessel(3, 5.0)); TEST_POLICY_SF(sph_bessel(3, 5)); TEST_POLICY_SF(sph_neumann(3, 5.0)); TEST_POLICY_SF(sph_neumann(3, 5)); return 0; }