489 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			489 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // Copyright 2008 Gautam Sewani | ||
|  | // Copyright 2008 John Maddock | ||
|  | // | ||
|  | // 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_DISTRIBUTIONS_DETAIL_HG_PDF_HPP | ||
|  | #define BOOST_MATH_DISTRIBUTIONS_DETAIL_HG_PDF_HPP | ||
|  | 
 | ||
|  | #include <boost/math/constants/constants.hpp> | ||
|  | #include <boost/math/special_functions/lanczos.hpp> | ||
|  | #include <boost/math/special_functions/gamma.hpp> | ||
|  | #include <boost/math/special_functions/pow.hpp> | ||
|  | #include <boost/math/special_functions/prime.hpp> | ||
|  | #include <boost/math/policies/error_handling.hpp> | ||
|  | 
 | ||
|  | #ifdef BOOST_MATH_INSTRUMENT | ||
|  | #include <typeinfo> | ||
|  | #endif | ||
|  | 
 | ||
|  | namespace boost{ namespace math{ namespace detail{ | ||
|  | 
 | ||
|  | template <class T, class Func> | ||
|  | void bubble_down_one(T* first, T* last, Func f) | ||
|  | { | ||
|  |    using std::swap; | ||
|  |    T* next = first; | ||
|  |    ++next; | ||
|  |    while((next != last) && (!f(*first, *next))) | ||
|  |    { | ||
|  |       swap(*first, *next); | ||
|  |       ++first; | ||
|  |       ++next; | ||
|  |    } | ||
|  | } | ||
|  | 
 | ||
|  | template <class T> | ||
|  | struct sort_functor | ||
|  | { | ||
|  |    sort_functor(const T* exponents) : m_exponents(exponents){} | ||
|  |    bool operator()(int i, int j) | ||
|  |    { | ||
|  |       return m_exponents[i] > m_exponents[j]; | ||
|  |    } | ||
|  | private: | ||
|  |    const T* m_exponents; | ||
|  | }; | ||
|  | 
 | ||
|  | template <class T, class Lanczos, class Policy> | ||
|  | T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n, unsigned N, const Lanczos&, const Policy&) | ||
|  | { | ||
|  |    BOOST_MATH_STD_USING | ||
|  | 
 | ||
|  |    BOOST_MATH_INSTRUMENT_FPU | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(x); | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(r); | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(n); | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(N); | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(typeid(Lanczos).name()); | ||
|  | 
 | ||
|  |    T bases[9] = { | ||
|  |       T(n) + static_cast<T>(Lanczos::g()) + 0.5f, | ||
|  |       T(r) + static_cast<T>(Lanczos::g()) + 0.5f, | ||
|  |       T(N - n) + static_cast<T>(Lanczos::g()) + 0.5f, | ||
|  |       T(N - r) + static_cast<T>(Lanczos::g()) + 0.5f, | ||
|  |       1 / (T(N) + static_cast<T>(Lanczos::g()) + 0.5f), | ||
|  |       1 / (T(x) + static_cast<T>(Lanczos::g()) + 0.5f), | ||
|  |       1 / (T(n - x) + static_cast<T>(Lanczos::g()) + 0.5f), | ||
|  |       1 / (T(r - x) + static_cast<T>(Lanczos::g()) + 0.5f), | ||
|  |       1 / (T(N - n - r + x) + static_cast<T>(Lanczos::g()) + 0.5f) | ||
|  |    }; | ||
|  |    T exponents[9] = { | ||
|  |       n + T(0.5f), | ||
|  |       r + T(0.5f), | ||
|  |       N - n + T(0.5f), | ||
|  |       N - r + T(0.5f), | ||
|  |       N + T(0.5f), | ||
|  |       x + T(0.5f), | ||
|  |       n - x + T(0.5f), | ||
|  |       r - x + T(0.5f), | ||
|  |       N - n - r + x + T(0.5f) | ||
|  |    }; | ||
|  |    int base_e_factors[9] = { | ||
|  |       -1, -1, -1, -1, 1, 1, 1, 1, 1 | ||
|  |    }; | ||
|  |    int sorted_indexes[9] = { | ||
|  |       0, 1, 2, 3, 4, 5, 6, 7, 8 | ||
|  |    }; | ||
|  | #ifdef BOOST_MATH_INSTRUMENT | ||
|  |    BOOST_MATH_INSTRUMENT_FPU | ||
|  |    for(unsigned i = 0; i < 9; ++i) | ||
|  |    { | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(i); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); | ||
|  |    } | ||
|  | #endif | ||
|  |    std::sort(sorted_indexes, sorted_indexes + 9, sort_functor<T>(exponents)); | ||
|  | #ifdef BOOST_MATH_INSTRUMENT | ||
|  |    BOOST_MATH_INSTRUMENT_FPU | ||
|  |    for(unsigned i = 0; i < 9; ++i) | ||
|  |    { | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(i); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); | ||
|  |    } | ||
|  | #endif | ||
|  | 
 | ||
|  |    do{ | ||
|  |       exponents[sorted_indexes[0]] -= exponents[sorted_indexes[1]]; | ||
|  |       bases[sorted_indexes[1]] *= bases[sorted_indexes[0]]; | ||
|  |       if((bases[sorted_indexes[1]] < tools::min_value<T>()) && (exponents[sorted_indexes[1]] != 0)) | ||
|  |       { | ||
|  |          return 0; | ||
|  |       } | ||
|  |       base_e_factors[sorted_indexes[1]] += base_e_factors[sorted_indexes[0]]; | ||
|  |       bubble_down_one(sorted_indexes, sorted_indexes + 9, sort_functor<T>(exponents)); | ||
|  | 
 | ||
|  | #ifdef BOOST_MATH_INSTRUMENT | ||
|  |       for(unsigned i = 0; i < 9; ++i) | ||
|  |       { | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(i); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); | ||
|  |       } | ||
|  | #endif | ||
|  |    }while(exponents[sorted_indexes[1]] > 1); | ||
|  | 
 | ||
|  |    // | ||
|  |    // Combine equal powers: | ||
|  |    // | ||
|  |    int j = 8; | ||
|  |    while(exponents[sorted_indexes[j]] == 0) --j; | ||
|  |    while(j) | ||
|  |    { | ||
|  |       while(j && (exponents[sorted_indexes[j-1]] == exponents[sorted_indexes[j]])) | ||
|  |       { | ||
|  |          bases[sorted_indexes[j-1]] *= bases[sorted_indexes[j]]; | ||
|  |          exponents[sorted_indexes[j]] = 0; | ||
|  |          base_e_factors[sorted_indexes[j-1]] += base_e_factors[sorted_indexes[j]]; | ||
|  |          bubble_down_one(sorted_indexes + j, sorted_indexes + 9, sort_functor<T>(exponents)); | ||
|  |          --j; | ||
|  |       } | ||
|  |       --j; | ||
|  | 
 | ||
|  | #ifdef BOOST_MATH_INSTRUMENT | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(j); | ||
|  |       for(unsigned i = 0; i < 9; ++i) | ||
|  |       { | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(i); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); | ||
|  |          BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); | ||
|  |       } | ||
|  | #endif | ||
|  |    } | ||
|  | 
 | ||
|  | #ifdef BOOST_MATH_INSTRUMENT | ||
|  |    BOOST_MATH_INSTRUMENT_FPU | ||
|  |    for(unsigned i = 0; i < 9; ++i) | ||
|  |    { | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(i); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); | ||
|  |    } | ||
|  | #endif | ||
|  | 
 | ||
|  |    T result; | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(bases[sorted_indexes[0]] * exp(static_cast<T>(base_e_factors[sorted_indexes[0]]))); | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(exponents[sorted_indexes[0]]); | ||
|  |    { | ||
|  |       BOOST_FPU_EXCEPTION_GUARD | ||
|  |       result = pow(bases[sorted_indexes[0]] * exp(static_cast<T>(base_e_factors[sorted_indexes[0]])), exponents[sorted_indexes[0]]); | ||
|  |    } | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(result); | ||
|  |    for(unsigned i = 1; (i < 9) && (exponents[sorted_indexes[i]] > 0); ++i) | ||
|  |    { | ||
|  |       BOOST_FPU_EXCEPTION_GUARD | ||
|  |       if(result < tools::min_value<T>()) | ||
|  |          return 0; // short circuit further evaluation | ||
|  |       if(exponents[sorted_indexes[i]] == 1) | ||
|  |          result *= bases[sorted_indexes[i]] * exp(static_cast<T>(base_e_factors[sorted_indexes[i]])); | ||
|  |       else if(exponents[sorted_indexes[i]] == 0.5f) | ||
|  |          result *= sqrt(bases[sorted_indexes[i]] * exp(static_cast<T>(base_e_factors[sorted_indexes[i]]))); | ||
|  |       else | ||
|  |          result *= pow(bases[sorted_indexes[i]] * exp(static_cast<T>(base_e_factors[sorted_indexes[i]])), exponents[sorted_indexes[i]]); | ||
|  |     | ||
|  |       BOOST_MATH_INSTRUMENT_VARIABLE(result); | ||
|  |    } | ||
|  | 
 | ||
|  |    result *= Lanczos::lanczos_sum_expG_scaled(static_cast<T>(n + 1)) | ||
|  |       * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(r + 1)) | ||
|  |       * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N - n + 1)) | ||
|  |       * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N - r + 1)) | ||
|  |       /  | ||
|  |       ( Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N + 1)) | ||
|  |          * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(x + 1)) | ||
|  |          * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(n - x + 1)) | ||
|  |          * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(r - x + 1)) | ||
|  |          * Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N - n - r + x + 1))); | ||
|  |     | ||
|  |    BOOST_MATH_INSTRUMENT_VARIABLE(result); | ||
|  |    return result; | ||
|  | } | ||
|  | 
 | ||
|  | template <class T, class Policy> | ||
|  | T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n, unsigned N, const boost::math::lanczos::undefined_lanczos&, const Policy& pol) | ||
|  | { | ||
|  |    BOOST_MATH_STD_USING | ||
|  |    return exp( | ||
|  |       boost::math::lgamma(T(n + 1), pol) | ||
|  |       + boost::math::lgamma(T(r + 1), pol) | ||
|  |       + boost::math::lgamma(T(N - n + 1), pol) | ||
|  |       + boost::math::lgamma(T(N - r + 1), pol) | ||
|  |       - boost::math::lgamma(T(N + 1), pol) | ||
|  |       - boost::math::lgamma(T(x + 1), pol) | ||
|  |       - boost::math::lgamma(T(n - x + 1), pol) | ||
|  |       - boost::math::lgamma(T(r - x + 1), pol) | ||
|  |       - boost::math::lgamma(T(N - n - r + x + 1), pol)); | ||
|  | } | ||
|  | 
 | ||
|  | template <class T> | ||
|  | inline T integer_power(const T& x, int ex) | ||
|  | { | ||
|  |    if(ex < 0) | ||
|  |       return 1 / integer_power(x, -ex); | ||
|  |    switch(ex) | ||
|  |    { | ||
|  |    case 0: | ||
|  |       return 1; | ||
|  |    case 1: | ||
|  |       return x; | ||
|  |    case 2: | ||
|  |       return x * x; | ||
|  |    case 3: | ||
|  |       return x * x * x; | ||
|  |    case 4: | ||
|  |       return boost::math::pow<4>(x); | ||
|  |    case 5: | ||
|  |       return boost::math::pow<5>(x); | ||
|  |    case 6: | ||
|  |       return boost::math::pow<6>(x); | ||
|  |    case 7: | ||
|  |       return boost::math::pow<7>(x); | ||
|  |    case 8: | ||
|  |       return boost::math::pow<8>(x); | ||
|  |    } | ||
|  |    BOOST_MATH_STD_USING | ||
|  | #ifdef __SUNPRO_CC | ||
|  |    return pow(x, T(ex)); | ||
|  | #else | ||
|  |    return pow(x, ex); | ||
|  | #endif | ||
|  | } | ||
|  | template <class T> | ||
|  | struct hypergeometric_pdf_prime_loop_result_entry | ||
|  | { | ||
|  |    T value; | ||
|  |    const hypergeometric_pdf_prime_loop_result_entry* next; | ||
|  | }; | ||
|  | 
 | ||
|  | #ifdef BOOST_MSVC | ||
|  | #pragma warning(push) | ||
|  | #pragma warning(disable:4510 4512 4610) | ||
|  | #endif | ||
|  | 
 | ||
|  | struct hypergeometric_pdf_prime_loop_data | ||
|  | { | ||
|  |    const unsigned x; | ||
|  |    const unsigned r; | ||
|  |    const unsigned n; | ||
|  |    const unsigned N; | ||
|  |    unsigned prime_index; | ||
|  |    unsigned current_prime; | ||
|  | }; | ||
|  | 
 | ||
|  | #ifdef BOOST_MSVC | ||
|  | #pragma warning(pop) | ||
|  | #endif | ||
|  | 
 | ||
|  | template <class T> | ||
|  | T hypergeometric_pdf_prime_loop_imp(hypergeometric_pdf_prime_loop_data& data, hypergeometric_pdf_prime_loop_result_entry<T>& result) | ||
|  | { | ||
|  |    while(data.current_prime <= data.N) | ||
|  |    { | ||
|  |       unsigned base = data.current_prime; | ||
|  |       int prime_powers = 0; | ||
|  |       while(base <= data.N) | ||
|  |       { | ||
|  |          prime_powers += data.n / base; | ||
|  |          prime_powers += data.r / base; | ||
|  |          prime_powers += (data.N - data.n) / base; | ||
|  |          prime_powers += (data.N - data.r) / base; | ||
|  |          prime_powers -= data.N / base; | ||
|  |          prime_powers -= data.x / base; | ||
|  |          prime_powers -= (data.n - data.x) / base; | ||
|  |          prime_powers -= (data.r - data.x) / base; | ||
|  |          prime_powers -= (data.N - data.n - data.r + data.x) / base; | ||
|  |          base *= data.current_prime; | ||
|  |       } | ||
|  |       if(prime_powers) | ||
|  |       { | ||
|  |          T p = integer_power<T>(static_cast<T>(data.current_prime), prime_powers); | ||
|  |          if((p > 1) && (tools::max_value<T>() / p < result.value)) | ||
|  |          { | ||
|  |             // | ||
|  |             // The next calculation would overflow, use recursion | ||
|  |             // to sidestep the issue: | ||
|  |             // | ||
|  |             hypergeometric_pdf_prime_loop_result_entry<T> t = { p, &result }; | ||
|  |             data.current_prime = prime(++data.prime_index); | ||
|  |             return hypergeometric_pdf_prime_loop_imp<T>(data, t); | ||
|  |          } | ||
|  |          if((p < 1) && (tools::min_value<T>() / p > result.value)) | ||
|  |          { | ||
|  |             // | ||
|  |             // The next calculation would underflow, use recursion | ||
|  |             // to sidestep the issue: | ||
|  |             // | ||
|  |             hypergeometric_pdf_prime_loop_result_entry<T> t = { p, &result }; | ||
|  |             data.current_prime = prime(++data.prime_index); | ||
|  |             return hypergeometric_pdf_prime_loop_imp<T>(data, t); | ||
|  |          } | ||
|  |          result.value *= p; | ||
|  |       } | ||
|  |       data.current_prime = prime(++data.prime_index); | ||
|  |    } | ||
|  |    // | ||
|  |    // When we get to here we have run out of prime factors, | ||
|  |    // the overall result is the product of all the partial | ||
|  |    // results we have accumulated on the stack so far, these | ||
|  |    // are in a linked list starting with "data.head" and ending | ||
|  |    // with "result". | ||
|  |    // | ||
|  |    // All that remains is to multiply them together, taking | ||
|  |    // care not to overflow or underflow. | ||
|  |    // | ||
|  |    // Enumerate partial results >= 1 in variable i | ||
|  |    // and partial results < 1 in variable j: | ||
|  |    // | ||
|  |    hypergeometric_pdf_prime_loop_result_entry<T> const *i, *j; | ||
|  |    i = &result; | ||
|  |    while(i && i->value < 1) | ||
|  |       i = i->next; | ||
|  |    j = &result; | ||
|  |    while(j && j->value >= 1) | ||
|  |       j = j->next; | ||
|  | 
 | ||
|  |    T prod = 1; | ||
|  | 
 | ||
|  |    while(i || j) | ||
|  |    { | ||
|  |       while(i && ((prod <= 1) || (j == 0))) | ||
|  |       { | ||
|  |          prod *= i->value; | ||
|  |          i = i->next; | ||
|  |          while(i && i->value < 1) | ||
|  |             i = i->next; | ||
|  |       } | ||
|  |       while(j && ((prod >= 1) || (i == 0))) | ||
|  |       { | ||
|  |          prod *= j->value; | ||
|  |          j = j->next; | ||
|  |          while(j && j->value >= 1) | ||
|  |             j = j->next; | ||
|  |       } | ||
|  |    } | ||
|  | 
 | ||
|  |    return prod; | ||
|  | } | ||
|  | 
 | ||
|  | template <class T, class Policy> | ||
|  | inline T hypergeometric_pdf_prime_imp(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&) | ||
|  | { | ||
|  |    hypergeometric_pdf_prime_loop_result_entry<T> result = { 1, 0 }; | ||
|  |    hypergeometric_pdf_prime_loop_data data = { x, r, n, N, 0, prime(0) }; | ||
|  |    return hypergeometric_pdf_prime_loop_imp<T>(data, result); | ||
|  | } | ||
|  | 
 | ||
|  | template <class T, class Policy> | ||
|  | T hypergeometric_pdf_factorial_imp(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&) | ||
|  | { | ||
|  |    BOOST_MATH_STD_USING | ||
|  |    BOOST_ASSERT(N <= boost::math::max_factorial<T>::value); | ||
|  |    T result = boost::math::unchecked_factorial<T>(n); | ||
|  |    T num[3] = { | ||
|  |       boost::math::unchecked_factorial<T>(r), | ||
|  |       boost::math::unchecked_factorial<T>(N - n), | ||
|  |       boost::math::unchecked_factorial<T>(N - r) | ||
|  |    }; | ||
|  |    T denom[5] = { | ||
|  |       boost::math::unchecked_factorial<T>(N), | ||
|  |       boost::math::unchecked_factorial<T>(x), | ||
|  |       boost::math::unchecked_factorial<T>(n - x), | ||
|  |       boost::math::unchecked_factorial<T>(r - x), | ||
|  |       boost::math::unchecked_factorial<T>(N - n - r + x) | ||
|  |    }; | ||
|  |    int i = 0; | ||
|  |    int j = 0; | ||
|  |    while((i < 3) || (j < 5)) | ||
|  |    { | ||
|  |       while((j < 5) && ((result >= 1) || (i >= 3))) | ||
|  |       { | ||
|  |          result /= denom[j]; | ||
|  |          ++j; | ||
|  |       } | ||
|  |       while((i < 3) && ((result <= 1) || (j >= 5))) | ||
|  |       { | ||
|  |          result *= num[i]; | ||
|  |          ++i; | ||
|  |       } | ||
|  |    } | ||
|  |    return result; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | template <class T, class Policy> | ||
|  | inline typename tools::promote_args<T>::type  | ||
|  |    hypergeometric_pdf(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&) | ||
|  | { | ||
|  |    BOOST_FPU_EXCEPTION_GUARD | ||
|  |    typedef typename tools::promote_args<T>::type result_type; | ||
|  |    typedef typename policies::evaluation<result_type, Policy>::type value_type; | ||
|  |    typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type; | ||
|  |    typedef typename policies::normalise< | ||
|  |       Policy,  | ||
|  |       policies::promote_float<false>,  | ||
|  |       policies::promote_double<false>,  | ||
|  |       policies::discrete_quantile<>, | ||
|  |       policies::assert_undefined<> >::type forwarding_policy; | ||
|  | 
 | ||
|  |    value_type result; | ||
|  |    if(N <= boost::math::max_factorial<value_type>::value) | ||
|  |    { | ||
|  |       // | ||
|  |       // If N is small enough then we can evaluate the PDF via the factorials | ||
|  |       // directly: table lookup of the factorials gives the best performance | ||
|  |       // of the methods available: | ||
|  |       // | ||
|  |       result = detail::hypergeometric_pdf_factorial_imp<value_type>(x, r, n, N, forwarding_policy()); | ||
|  |    } | ||
|  |    else if(N <= boost::math::prime(boost::math::max_prime - 1)) | ||
|  |    { | ||
|  |       // | ||
|  |       // If N is no larger than the largest prime number in our lookup table | ||
|  |       // (104729) then we can use prime factorisation to evaluate the PDF, | ||
|  |       // this is slow but accurate: | ||
|  |       // | ||
|  |       result = detail::hypergeometric_pdf_prime_imp<value_type>(x, r, n, N, forwarding_policy()); | ||
|  |    } | ||
|  |    else | ||
|  |    { | ||
|  |       // | ||
|  |       // Catch all case - use the lanczos approximation - where available -  | ||
|  |       // to evaluate the ratio of factorials.  This is reasonably fast | ||
|  |       // (almost as quick as using logarithmic evaluation in terms of lgamma) | ||
|  |       // but only a few digits better in accuracy than using lgamma: | ||
|  |       // | ||
|  |       result = detail::hypergeometric_pdf_lanczos_imp(value_type(), x, r, n, N, evaluation_type(), forwarding_policy()); | ||
|  |    } | ||
|  | 
 | ||
|  |    if(result > 1) | ||
|  |    { | ||
|  |       result = 1; | ||
|  |    } | ||
|  |    if(result < 0) | ||
|  |    { | ||
|  |       result = 0; | ||
|  |    } | ||
|  | 
 | ||
|  |    return policies::checked_narrowing_cast<result_type, forwarding_policy>(result, "boost::math::hypergeometric_pdf<%1%>(%1%,%1%,%1%,%1%)"); | ||
|  | } | ||
|  | 
 | ||
|  | }}} // namespaces | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 |