beta.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,357 行 · 第 1/3 页
HPP
1,357 行
if(normalised) { T c = a + b; // incomplete beta power term, combined with the Lanczos approximation: T agh = a + L::g() - T(0.5); T bgh = b + L::g() - T(0.5); T cgh = c + L::g() - T(0.5); result = L::lanczos_sum_expG_scaled(c) / (L::lanczos_sum_expG_scaled(a) * L::lanczos_sum_expG_scaled(b)); if(a * b < bgh * 10) result *= exp((b - 0.5f) * boost::math::log1p(a / bgh, pol)); else result *= pow(cgh / bgh, b - 0.5f); result *= pow(x * cgh / agh, a); result *= sqrt(agh / boost::math::constants::e<T>()); if(p_derivative) { *p_derivative = result * pow(y, b); BOOST_ASSERT(*p_derivative >= 0); } } else { // Non-normalised, just compute the power: result = pow(x, a); } if(result < tools::min_value<T>()) return s0; // Safeguard: series can't cope with denorms. ibeta_series_t<T> s(a, b, x, result); boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>(); result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter, s0); policies::check_series_iterations("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (with lanczos)", max_iter, pol); return result;}//// Incomplete Beta series again, this time without Lanczos support://template <class T, class Policy>T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol){ BOOST_MATH_STD_USING T result; BOOST_ASSERT((p_derivative == 0) || normalised); if(normalised) { T prefix = 1; T c = a + b; // figure out integration limits for the gamma function: //T la = (std::max)(T(10), a); //T lb = (std::max)(T(10), b); //T lc = (std::max)(T(10), a+b); T la = a + 5; T lb = b + 5; T lc = a + b + 5; // calculate the gamma parts: T sa = detail::lower_gamma_series(a, la, pol) / a; sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::digits<T, Policy>()); T sb = detail::lower_gamma_series(b, lb, pol) / b; sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits<T, Policy>()); T sc = detail::lower_gamma_series(c, lc, pol) / c; sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits<T, Policy>()); // and their combined power-terms: T b1 = (x * lc) / la; T b2 = lc/lb; T e1 = lc - la - lb; T lb1 = a * log(b1); T lb2 = b * log(b2); if((lb1 >= tools::log_max_value<T>()) || (lb1 <= tools::log_min_value<T>()) || (lb2 >= tools::log_max_value<T>()) || (lb2 <= tools::log_min_value<T>()) || (e1 >= tools::log_max_value<T>()) || (e1 <= tools::log_min_value<T>()) ) { T p = lb1 + lb2 - e1; result = exp(p); } else { result = pow(b1, a); if(a * b < lb * 10) result *= exp(b * boost::math::log1p(a / lb, pol)); else result *= pow(b2, b); result /= exp(e1); } // and combine the results: result /= sa * sb / sc; if(p_derivative) { *p_derivative = result * pow(y, b); BOOST_ASSERT(*p_derivative >= 0); } } else { // Non-normalised, just compute the power: result = pow(x, a); } if(result < tools::min_value<T>()) return s0; // Safeguard: series can't cope with denorms. ibeta_series_t<T> s(a, b, x, result); boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>(); result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter, s0); policies::check_series_iterations("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (without lanczos)", max_iter, pol); return result;}//// Continued fraction for the incomplete beta://template <class T>struct ibeta_fraction2_t{ typedef std::pair<T, T> result_type; ibeta_fraction2_t(T a_, T b_, T x_) : a(a_), b(b_), x(x_), m(0) {} result_type operator()() { T aN = (a + m - 1) * (a + b + m - 1) * m * (b - m) * x * x; T denom = (a + 2 * m - 1); aN /= denom * denom; T bN = m; bN += (m * (b - m) * x) / (a + 2*m - 1); bN += ((a + m) * (a - (a + b) * x + 1 + m *(2 - x))) / (a + 2*m + 1); ++m; return std::make_pair(aN, bN); }private: T a, b, x; int m;};//// Evaluate the incomplete beta via the continued fraction representation://template <class T, class Policy>inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, T* p_derivative){ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type; BOOST_MATH_STD_USING T result = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol); if(p_derivative) { *p_derivative = result; BOOST_ASSERT(*p_derivative >= 0); } if(result == 0) return result; ibeta_fraction2_t<T> f(a, b, x); T fract = boost::math::tools::continued_fraction_b(f, boost::math::policies::digits<T, Policy>()); return result / fract;}//// Computes the difference between ibeta(a,b,x) and ibeta(a+k,b,x)://template <class T, class Policy>T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* p_derivative){ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type; T prefix = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol); if(p_derivative) { *p_derivative = prefix; BOOST_ASSERT(*p_derivative >= 0); } prefix /= a; if(prefix == 0) return prefix; T sum = 1; T term = 1; // series summation from 0 to k-1: for(int i = 0; i < k-1; ++i) { term *= (a+b+i) * x / (a+i+1); sum += term; } prefix *= sum; return prefix;}//// This function is only needed for the non-regular incomplete beta,// it computes the delta in:// beta(a,b,x) = prefix + delta * beta(a+k,b,x)// it is currently only called for small k.//template <class T>inline T rising_factorial_ratio(T a, T b, int k){ // calculate: // (a)(a+1)(a+2)...(a+k-1) // _______________________ // (b)(b+1)(b+2)...(b+k-1) // This is only called with small k, for large k // it is grossly inefficient, do not use outside it's // intended purpose!!! if(k == 0) return 1; T result = 1; for(int i = 0; i < k; ++i) result *= (a+i) / (b+i); return result;}//// Routine for a > 15, b < 1//// Begin by figuring out how large our table of Pn's should be,// quoted accuracies are "guestimates" based on empiracal observation.// Note that the table size should never exceed the size of our// tables of factorials.//template <class T>struct Pn_size{ // This is likely to be enough for ~35-50 digit accuracy // but it's hard to quantify exactly: BOOST_STATIC_CONSTANT(unsigned, value = 50); BOOST_STATIC_ASSERT(::boost::math::max_factorial<T>::value >= 100);};template <>struct Pn_size<float>{ BOOST_STATIC_CONSTANT(unsigned, value = 15); // ~8-15 digit accuracy BOOST_STATIC_ASSERT(::boost::math::max_factorial<float>::value >= 30);};template <>struct Pn_size<double>{ BOOST_STATIC_CONSTANT(unsigned, value = 30); // 16-20 digit accuracy BOOST_STATIC_ASSERT(::boost::math::max_factorial<double>::value >= 60);};template <>struct Pn_size<long double>{ BOOST_STATIC_CONSTANT(unsigned, value = 50); // ~35-50 digit accuracy BOOST_STATIC_ASSERT(::boost::math::max_factorial<long double>::value >= 100);};template <class T, class Policy>T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& pol, bool normalised){ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type; BOOST_MATH_STD_USING // // This is DiDonato and Morris's BGRAT routine, see Eq's 9 through 9.6. // // Some values we'll need later, these are Eq 9.1: // T bm1 = b - 1; T t = a + bm1 / 2; T lx, u; if(y < 0.35) lx = boost::math::log1p(-y, pol); else lx = log(x); u = -t * lx; // and from from 9.2: T prefix; T h = regularised_gamma_prefix(b, u, pol, lanczos_type()); if(h <= tools::min_value<T>()) return s0; if(normalised) { prefix = h / boost::math::tgamma_delta_ratio(a, b, pol); prefix /= pow(t, b); } else { prefix = full_igamma_prefix(b, u, pol) / pow(t, b); } prefix *= mult; // // now we need the quantity Pn, unfortunatately this is computed // recursively, and requires a full history of all the previous values // so no choice but to declare a big table and hope it's big enough... // T p[ ::boost::math::detail::Pn_size<T>::value ] = { 1 }; // see 9.3. // // Now an initial value for J, see 9.6: // T j = boost::math::gamma_q(b, u, pol) / h; // // Now we can start to pull things together and evaluate the sum in Eq 9: // T sum = s0 + prefix * j; // Value at N = 0 // some variables we'll need: unsigned tnp1 = 1; // 2*N+1 T lx2 = lx / 2; lx2 *= lx2; T lxp = 1; T t4 = 4 * t * t; T b2n = b; for(unsigned n = 1; n < sizeof(p)/sizeof(p[0]); ++n) { /* // debugging code, enable this if you want to determine whether // the table of Pn's is large enough... // static int max_count = 2; if(n > max_count) { max_count = n; std::cerr << "Max iterations in BGRAT was " << n << std::endl; } */ // // begin by evaluating the next Pn from Eq 9.4: // tnp1 += 2; p[n] = 0; T mbn = b - n; unsigned tmp1 = 3; for(unsigned m = 1; m < n; ++m) { mbn = m * b - n; p[n] += mbn * p[n-m] / boost::math::unchecked_factorial<T>(tmp1); tmp1 += 2; } p[n] /= n; p[n] += bm1 / boost::math::unchecked_factorial<T>(tnp1); // // Now we want Jn from Jn-1 using Eq 9.6: // j = (b2n * (b2n + 1) * j + (u + b2n + 1) * lxp) / t4; lxp *= lx2; b2n += 2; // // pull it together with Eq 9: // T r = prefix * p[n] * j; sum += r; if(r > 1) { if(fabs(r) < fabs(tools::epsilon<T>() * sum)) break; } else { if(fabs(r / tools::epsilon<T>()) < fabs(sum)) break; } } return sum;} // template <class T, class L>T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const L& l, bool normalised)//// For integer arguments we can relate the incomplete beta to the// complement of the binomial distribution cdf and use this finite sum.//template <class T>inline T binomial_ccdf(T n, T k, T x, T y){ BOOST_MATH_STD_USING // ADL of std names T result = pow(x, n); T term = result; for(unsigned i = itrunc(n - 1); i > k; --i) { term *= ((i + 1) * y) / ((n - i) * x) ; result += term; } return result;}//// The incomplete beta function implementation:// This is just a big bunch of spagetti code to divide up the// input range and select the right implementation method for// each domain://template <class T, class Policy>T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative){ static const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)"; typedef typename lanczos::lanczos<T, Policy>::type lanczos_type; BOOST_MATH_STD_USING // for ADL of std math functions. bool invert = inv; T fract; T y = 1 - x; BOOST_ASSERT((p_derivative == 0) || normalised); if(p_derivative) *p_derivative = -1; // value not set. if(normalised) { // extend to a few very special cases: if((a == 0) && (b != 0)) return inv ? 0 : 1; else if(b == 0) return inv ? 1 : 0; } if(a <= 0) policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol); if(b <= 0) policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol); if((x < 0) || (x > 1)) policies::raise_domain_error<T>(function, "Parameter x outside the range [0,1] in the incomplete beta function (got x=%1%).", x, pol); if(x == 0) { if(p_derivative) { *p_derivative = (a == 1) ? 1 : (a < 1) ? tools::max_value<T>() / 2 : tools::min_value<T>() * 2; } return (invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0); } if(x == 1) { if(p_derivative) { *p_derivative = (b == 1) ? 1 : (b < 1) ? tools::max_value<T>() / 2 : tools::min_value<T>() * 2; } return (invert == 0 ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0); } if((std::min)(a, b) <= 1) { if(x > 0.5) { std::swap(a, b); std::swap(x, y); invert = !invert; } if((std::max)(a, b) <= 1) { // Both a,b < 1: if((a >= (std::min)(T(0.2), b)) || (pow(x, a) <= 0.9)) { if(!invert) fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol); else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?