ibeta_inverse.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 940 行 · 第 1/3 页
HPP
940 行
// Copyright John Maddock 2006.// Copyright Paul A. Bristow 2007// 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_FUNCTIONS_IBETA_INVERSE_HPP#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP#ifdef _MSC_VER#pragma once#endif#include <boost/math/special_functions/beta.hpp>#include <boost/math/special_functions/erf.hpp>#include <boost/math/tools/roots.hpp>#include <boost/math/special_functions/detail/t_distribution_inv.hpp>namespace boost{ namespace math{ namespace detail{//// Helper object used by root finding// code to convert eta to x.//template <class T>struct temme_root_finder{ temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {} std::tr1::tuple<T, T> operator()(T x) { BOOST_MATH_STD_USING // ADL of std names T y = 1 - x; if(y == 0) { T big = tools::max_value<T>() / 4; return std::tr1::make_tuple(-big, -big); } if(x == 0) { T big = tools::max_value<T>() / 4; return std::tr1::make_tuple(-big, big); } T f = log(x) + a * log(y) + t; T f1 = (1 / x) - (a / (y)); return std::tr1::make_tuple(f, f1); }private: T t, a;};//// See:// "Asymptotic Inversion of the Incomplete Beta Function"// N.M. Temme// Journal of Computation and Applied Mathematics 41 (1992) 145-157.// Section 2.//template <class T, class Policy>T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol){ BOOST_MATH_STD_USING // ADL of std names const T r2 = sqrt(T(2)); // // get the first approximation for eta from the inverse // error function (Eq: 2.9 and 2.10). // T eta0 = boost::math::erfc_inv(2 * z, pol); eta0 /= -sqrt(a / 2); T terms[4] = { eta0 }; T workspace[7]; // // calculate powers: // T B = b - a; T B_2 = B * B; T B_3 = B_2 * B; // // Calculate correction terms: // // See eq following 2.15: workspace[0] = -B * r2 / 2; workspace[1] = (1 - 2 * B) / 8; workspace[2] = -(B * r2 / 48); workspace[3] = T(-1) / 192; workspace[4] = -B * r2 / 3840; terms[1] = tools::evaluate_polynomial(workspace, eta0, 5); // Eq Following 2.17: workspace[0] = B * r2 * (3 * B - 2) / 12; workspace[1] = (20 * B_2 - 12 * B + 1) / 128; workspace[2] = B * r2 * (20 * B - 1) / 960; workspace[3] = (16 * B_2 + 30 * B - 15) / 4608; workspace[4] = B * r2 * (21 * B + 32) / 53760; workspace[5] = (-32 * B_2 + 63) / 368640; workspace[6] = -B * r2 * (120 * B + 17) / 25804480; terms[2] = tools::evaluate_polynomial(workspace, eta0, 7); // Eq Following 2.17: workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480; workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216; workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760; workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640; terms[3] = tools::evaluate_polynomial(workspace, eta0, 4); // // Bring them together to get a final estimate for eta: // T eta = tools::evaluate_polynomial(terms, 1/a, 4); // // now we need to convert eta to x, by solving the appropriate // quadratic equation: // T eta_2 = eta * eta; T c = -exp(-eta_2 / 2); T x; if(eta_2 == 0) x = 0.5; else x = (1 + eta * sqrt((1 + c) / eta_2)) / 2; BOOST_ASSERT(x >= 0); BOOST_ASSERT(x <= 1); BOOST_ASSERT(eta * (x - 0.5) >= 0);#ifdef BOOST_INSTRUMENT std::cout << "Estimating x with Temme method 1: " << x << std::endl;#endif return x;}//// See:// "Asymptotic Inversion of the Incomplete Beta Function"// N.M. Temme// Journal of Computation and Applied Mathematics 41 (1992) 145-157.// Section 3.//template <class T, class Policy>T temme_method_2_ibeta_inverse(T /*a*/, T /*b*/, T z, T r, T theta, const Policy& pol){ BOOST_MATH_STD_USING // ADL of std names // // Get first estimate for eta, see Eq 3.9 and 3.10, // but note there is a typo in Eq 3.10: // T eta0 = boost::math::erfc_inv(2 * z, pol); eta0 /= -sqrt(r / 2); T s = sin(theta); T c = cos(theta); // // Now we need to purturb eta0 to get eta, which we do by // evaluating the polynomial in 1/r at the bottom of page 151, // to do this we first need the error terms e1, e2 e3 // which we'll fill into the array "terms". Since these // terms are themselves polynomials, we'll need another // array "workspace" to calculate those... // T terms[4] = { eta0 }; T workspace[6]; // // some powers of sin(theta)cos(theta) that we'll need later: // T sc = s * c; T sc_2 = sc * sc; T sc_3 = sc_2 * sc; T sc_4 = sc_2 * sc_2; T sc_5 = sc_2 * sc_3; T sc_6 = sc_3 * sc_3; T sc_7 = sc_4 * sc_3; // // Calculate e1 and put it in terms[1], see the middle of page 151: // workspace[0] = (2 * s * s - 1) / (3 * s * c); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 }; workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 }; workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 }; workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 }; workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5); terms[1] = tools::evaluate_polynomial(workspace, eta0, 5); // // Now evaluate e2 and put it in terms[2]: // static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 }; workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 }; workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 }; workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 }; workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6); terms[2] = tools::evaluate_polynomial(workspace, eta0, 4); // // And e3, and put it in terms[3]: // static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 }; workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 }; workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 }; workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7); terms[3] = tools::evaluate_polynomial(workspace, eta0, 3); // // Bring the correction terms together to evaluate eta, // this is the last equation on page 151: // T eta = tools::evaluate_polynomial(terms, 1/r, 4); // // Now that we have eta we need to back solve for x, // we seek the value of x that gives eta in Eq 3.2. // The two methods used are described in section 5. // // Begin by defining a few variables we'll need later: // T x; T s_2 = s * s; T c_2 = c * c; T alpha = c / s; alpha *= alpha; T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2); // // Temme doesn't specify what value to switch on here, // but this seems to work pretty well: // if(fabs(eta) < 0.7) { // // Small eta use the expansion Temme gives in the second equation // of section 5, it's a polynomial in eta: // workspace[0] = s * s; workspace[1] = s * c; workspace[2] = (1 - 2 * workspace[0]) / 3; static const BOOST_MATH_INT_TABLE_TYPE(T, int) co12[] = { 1, -13, 13 }; workspace[3] = tools::evaluate_polynomial(co12, workspace[0], 3) / (36 * s * c); static const BOOST_MATH_INT_TABLE_TYPE(T, int) co13[] = { 1, 21, -69, 46 }; workspace[4] = tools::evaluate_polynomial(co13, workspace[0], 4) / (270 * workspace[0] * c * c); x = tools::evaluate_polynomial(workspace, eta, 5);#ifdef BOOST_INSTRUMENT std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;#endif } else { // // If eta is large we need to solve Eq 3.2 more directly, // begin by getting an initial approximation for x from // the last equation on page 155, this is a polynomial in u: // T u = exp(lu); workspace[0] = u; workspace[1] = alpha; workspace[2] = 0; workspace[3] = 3 * alpha * (3 * alpha + 1) / 6; workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24; workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120; x = tools::evaluate_polynomial(workspace, u, 6); // // At this point we may or may not have the right answer, Eq-3.2 has // two solutions for x for any given eta, however the mapping in 3.2 // is 1:1 with the sign of eta and x-sin^2(theta) being the same. // So we can check if we have the right root of 3.2, and if not // switch x for 1-x. This transformation is motivated by the fact // that the distribution is *almost* symetric so 1-x will be in the right // ball park for the solution: // if((x - s_2) * eta < 0) x = 1 - x;#ifdef BOOST_INSTRUMENT std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;#endif } // // The final step is a few Newton-Raphson iterations to // clean up our approximation for x, this is pretty cheap // in general, and very cheap compared to an incomplete beta // evaluation. The limits set on x come from the observation // that the sign of eta and x-sin^2(theta) are the same. // T lower, upper; if(eta < 0) { lower = 0; upper = s_2; } else { lower = s_2; upper = 1; } // // If our initial approximation is out of bounds then bisect: // if((x < lower) || (x > upper)) x = (lower+upper) / 2; // // And iterate: // x = tools::newton_raphson_iterate( temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2); return x;}//// See:// "Asymptotic Inversion of the Incomplete Beta Function"// N.M. Temme// Journal of Computation and Applied Mathematics 41 (1992) 145-157.// Section 4.//template <class T, class Policy>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?