To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.
root / any / include / boost / math / distributions / detail / hypergeometric_pdf.hpp @ 160:cff480c41f97
History | View | Annotate | Download (15.6 KB)
| 1 |
// Copyright 2008 Gautam Sewani
|
|---|---|
| 2 |
// Copyright 2008 John Maddock
|
| 3 |
//
|
| 4 |
// Use, modification and distribution are subject to the
|
| 5 |
// Boost Software License, Version 1.0.
|
| 6 |
// (See accompanying file LICENSE_1_0.txt
|
| 7 |
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
| 8 |
|
| 9 |
#ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_HG_PDF_HPP
|
| 10 |
#define BOOST_MATH_DISTRIBUTIONS_DETAIL_HG_PDF_HPP
|
| 11 |
|
| 12 |
#include <boost/math/constants/constants.hpp> |
| 13 |
#include <boost/math/special_functions/lanczos.hpp> |
| 14 |
#include <boost/math/special_functions/gamma.hpp> |
| 15 |
#include <boost/math/special_functions/pow.hpp> |
| 16 |
#include <boost/math/special_functions/prime.hpp> |
| 17 |
#include <boost/math/policies/error_handling.hpp> |
| 18 |
|
| 19 |
#ifdef BOOST_MATH_INSTRUMENT
|
| 20 |
#include <typeinfo> |
| 21 |
#endif
|
| 22 |
|
| 23 |
namespace boost{ namespace math{ namespace detail{ |
| 24 |
|
| 25 |
template <class T, class Func> |
| 26 |
void bubble_down_one(T* first, T* last, Func f)
|
| 27 |
{
|
| 28 |
using std::swap;
|
| 29 |
T* next = first; |
| 30 |
++next; |
| 31 |
while((next != last) && (!f(*first, *next)))
|
| 32 |
{
|
| 33 |
swap(*first, *next); |
| 34 |
++first; |
| 35 |
++next; |
| 36 |
} |
| 37 |
} |
| 38 |
|
| 39 |
template <class T> |
| 40 |
struct sort_functor
|
| 41 |
{
|
| 42 |
sort_functor(const T* exponents) : m_exponents(exponents){}
|
| 43 |
bool operator()(int i, int j) |
| 44 |
{
|
| 45 |
return m_exponents[i] > m_exponents[j];
|
| 46 |
} |
| 47 |
private:
|
| 48 |
const T* m_exponents;
|
| 49 |
}; |
| 50 |
|
| 51 |
template <class T, class Lanczos, class Policy> |
| 52 |
T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n, unsigned N, const Lanczos&, const Policy&) |
| 53 |
{
|
| 54 |
BOOST_MATH_STD_USING |
| 55 |
|
| 56 |
BOOST_MATH_INSTRUMENT_FPU |
| 57 |
BOOST_MATH_INSTRUMENT_VARIABLE(x); |
| 58 |
BOOST_MATH_INSTRUMENT_VARIABLE(r); |
| 59 |
BOOST_MATH_INSTRUMENT_VARIABLE(n); |
| 60 |
BOOST_MATH_INSTRUMENT_VARIABLE(N); |
| 61 |
BOOST_MATH_INSTRUMENT_VARIABLE(typeid(Lanczos).name());
|
| 62 |
|
| 63 |
T bases[9] = {
|
| 64 |
T(n) + static_cast<T>(Lanczos::g()) + 0.5f, |
| 65 |
T(r) + static_cast<T>(Lanczos::g()) + 0.5f, |
| 66 |
T(N - n) + static_cast<T>(Lanczos::g()) + 0.5f, |
| 67 |
T(N - r) + static_cast<T>(Lanczos::g()) + 0.5f, |
| 68 |
1 / (T(N) + static_cast<T>(Lanczos::g()) + 0.5f), |
| 69 |
1 / (T(x) + static_cast<T>(Lanczos::g()) + 0.5f), |
| 70 |
1 / (T(n - x) + static_cast<T>(Lanczos::g()) + 0.5f), |
| 71 |
1 / (T(r - x) + static_cast<T>(Lanczos::g()) + 0.5f), |
| 72 |
1 / (T(N - n - r + x) + static_cast<T>(Lanczos::g()) + 0.5f) |
| 73 |
}; |
| 74 |
T exponents[9] = {
|
| 75 |
n + T(0.5f), |
| 76 |
r + T(0.5f), |
| 77 |
N - n + T(0.5f), |
| 78 |
N - r + T(0.5f), |
| 79 |
N + T(0.5f), |
| 80 |
x + T(0.5f), |
| 81 |
n - x + T(0.5f), |
| 82 |
r - x + T(0.5f), |
| 83 |
N - n - r + x + T(0.5f) |
| 84 |
}; |
| 85 |
int base_e_factors[9] = { |
| 86 |
-1, -1, -1, -1, 1, 1, 1, 1, 1 |
| 87 |
}; |
| 88 |
int sorted_indexes[9] = { |
| 89 |
0, 1, 2, 3, 4, 5, 6, 7, 8 |
| 90 |
}; |
| 91 |
#ifdef BOOST_MATH_INSTRUMENT
|
| 92 |
BOOST_MATH_INSTRUMENT_FPU |
| 93 |
for(unsigned i = 0; i < 9; ++i) |
| 94 |
{
|
| 95 |
BOOST_MATH_INSTRUMENT_VARIABLE(i); |
| 96 |
BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); |
| 97 |
BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); |
| 98 |
BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); |
| 99 |
BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); |
| 100 |
} |
| 101 |
#endif
|
| 102 |
std::sort(sorted_indexes, sorted_indexes + 9, sort_functor<T>(exponents));
|
| 103 |
#ifdef BOOST_MATH_INSTRUMENT
|
| 104 |
BOOST_MATH_INSTRUMENT_FPU |
| 105 |
for(unsigned i = 0; i < 9; ++i) |
| 106 |
{
|
| 107 |
BOOST_MATH_INSTRUMENT_VARIABLE(i); |
| 108 |
BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); |
| 109 |
BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); |
| 110 |
BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); |
| 111 |
BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); |
| 112 |
} |
| 113 |
#endif
|
| 114 |
|
| 115 |
do{
|
| 116 |
exponents[sorted_indexes[0]] -= exponents[sorted_indexes[1]]; |
| 117 |
bases[sorted_indexes[1]] *= bases[sorted_indexes[0]]; |
| 118 |
if((bases[sorted_indexes[1]] < tools::min_value<T>()) && (exponents[sorted_indexes[1]] != 0)) |
| 119 |
{
|
| 120 |
return 0; |
| 121 |
} |
| 122 |
base_e_factors[sorted_indexes[1]] += base_e_factors[sorted_indexes[0]]; |
| 123 |
bubble_down_one(sorted_indexes, sorted_indexes + 9, sort_functor<T>(exponents));
|
| 124 |
|
| 125 |
#ifdef BOOST_MATH_INSTRUMENT
|
| 126 |
for(unsigned i = 0; i < 9; ++i) |
| 127 |
{
|
| 128 |
BOOST_MATH_INSTRUMENT_VARIABLE(i); |
| 129 |
BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); |
| 130 |
BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); |
| 131 |
BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); |
| 132 |
BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); |
| 133 |
} |
| 134 |
#endif
|
| 135 |
}while(exponents[sorted_indexes[1]] > 1); |
| 136 |
|
| 137 |
//
|
| 138 |
// Combine equal powers:
|
| 139 |
//
|
| 140 |
int j = 8; |
| 141 |
while(exponents[sorted_indexes[j]] == 0) --j; |
| 142 |
while(j)
|
| 143 |
{
|
| 144 |
while(j && (exponents[sorted_indexes[j-1]] == exponents[sorted_indexes[j]])) |
| 145 |
{
|
| 146 |
bases[sorted_indexes[j-1]] *= bases[sorted_indexes[j]];
|
| 147 |
exponents[sorted_indexes[j]] = 0;
|
| 148 |
base_e_factors[sorted_indexes[j-1]] += base_e_factors[sorted_indexes[j]];
|
| 149 |
bubble_down_one(sorted_indexes + j, sorted_indexes + 9, sort_functor<T>(exponents));
|
| 150 |
--j; |
| 151 |
} |
| 152 |
--j; |
| 153 |
|
| 154 |
#ifdef BOOST_MATH_INSTRUMENT
|
| 155 |
BOOST_MATH_INSTRUMENT_VARIABLE(j); |
| 156 |
for(unsigned i = 0; i < 9; ++i) |
| 157 |
{
|
| 158 |
BOOST_MATH_INSTRUMENT_VARIABLE(i); |
| 159 |
BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); |
| 160 |
BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); |
| 161 |
BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); |
| 162 |
BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); |
| 163 |
} |
| 164 |
#endif
|
| 165 |
} |
| 166 |
|
| 167 |
#ifdef BOOST_MATH_INSTRUMENT
|
| 168 |
BOOST_MATH_INSTRUMENT_FPU |
| 169 |
for(unsigned i = 0; i < 9; ++i) |
| 170 |
{
|
| 171 |
BOOST_MATH_INSTRUMENT_VARIABLE(i); |
| 172 |
BOOST_MATH_INSTRUMENT_VARIABLE(bases[i]); |
| 173 |
BOOST_MATH_INSTRUMENT_VARIABLE(exponents[i]); |
| 174 |
BOOST_MATH_INSTRUMENT_VARIABLE(base_e_factors[i]); |
| 175 |
BOOST_MATH_INSTRUMENT_VARIABLE(sorted_indexes[i]); |
| 176 |
} |
| 177 |
#endif
|
| 178 |
|
| 179 |
T result; |
| 180 |
BOOST_MATH_INSTRUMENT_VARIABLE(bases[sorted_indexes[0]] * exp(static_cast<T>(base_e_factors[sorted_indexes[0]]))); |
| 181 |
BOOST_MATH_INSTRUMENT_VARIABLE(exponents[sorted_indexes[0]]);
|
| 182 |
{
|
| 183 |
BOOST_FPU_EXCEPTION_GUARD |
| 184 |
result = pow(bases[sorted_indexes[0]] * exp(static_cast<T>(base_e_factors[sorted_indexes[0]])), exponents[sorted_indexes[0]]); |
| 185 |
} |
| 186 |
BOOST_MATH_INSTRUMENT_VARIABLE(result); |
| 187 |
for(unsigned i = 1; (i < 9) && (exponents[sorted_indexes[i]] > 0); ++i) |
| 188 |
{
|
| 189 |
BOOST_FPU_EXCEPTION_GUARD |
| 190 |
if(result < tools::min_value<T>())
|
| 191 |
return 0; // short circuit further evaluation |
| 192 |
if(exponents[sorted_indexes[i]] == 1) |
| 193 |
result *= bases[sorted_indexes[i]] * exp(static_cast<T>(base_e_factors[sorted_indexes[i]]));
|
| 194 |
else if(exponents[sorted_indexes[i]] == 0.5f) |
| 195 |
result *= sqrt(bases[sorted_indexes[i]] * exp(static_cast<T>(base_e_factors[sorted_indexes[i]])));
|
| 196 |
else
|
| 197 |
result *= pow(bases[sorted_indexes[i]] * exp(static_cast<T>(base_e_factors[sorted_indexes[i]])), exponents[sorted_indexes[i]]);
|
| 198 |
|
| 199 |
BOOST_MATH_INSTRUMENT_VARIABLE(result); |
| 200 |
} |
| 201 |
|
| 202 |
result *= Lanczos::lanczos_sum_expG_scaled(static_cast<T>(n + 1)) |
| 203 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(r + 1)) |
| 204 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N - n + 1)) |
| 205 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N - r + 1)) |
| 206 |
/ |
| 207 |
( Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N + 1)) |
| 208 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(x + 1)) |
| 209 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(n - x + 1)) |
| 210 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(r - x + 1)) |
| 211 |
* Lanczos::lanczos_sum_expG_scaled(static_cast<T>(N - n - r + x + 1))); |
| 212 |
|
| 213 |
BOOST_MATH_INSTRUMENT_VARIABLE(result); |
| 214 |
return result;
|
| 215 |
} |
| 216 |
|
| 217 |
template <class T, class Policy> |
| 218 |
T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n, unsigned N, const boost::math::lanczos::undefined_lanczos&, const Policy& pol) |
| 219 |
{
|
| 220 |
BOOST_MATH_STD_USING |
| 221 |
return exp(
|
| 222 |
boost::math::lgamma(T(n + 1), pol)
|
| 223 |
+ boost::math::lgamma(T(r + 1), pol)
|
| 224 |
+ boost::math::lgamma(T(N - n + 1), pol)
|
| 225 |
+ boost::math::lgamma(T(N - r + 1), pol)
|
| 226 |
- boost::math::lgamma(T(N + 1), pol)
|
| 227 |
- boost::math::lgamma(T(x + 1), pol)
|
| 228 |
- boost::math::lgamma(T(n - x + 1), pol)
|
| 229 |
- boost::math::lgamma(T(r - x + 1), pol)
|
| 230 |
- boost::math::lgamma(T(N - n - r + x + 1), pol));
|
| 231 |
} |
| 232 |
|
| 233 |
template <class T> |
| 234 |
inline T integer_power(const T& x, int ex) |
| 235 |
{
|
| 236 |
if(ex < 0) |
| 237 |
return 1 / integer_power(x, -ex); |
| 238 |
switch(ex)
|
| 239 |
{
|
| 240 |
case 0: |
| 241 |
return 1; |
| 242 |
case 1: |
| 243 |
return x;
|
| 244 |
case 2: |
| 245 |
return x * x;
|
| 246 |
case 3: |
| 247 |
return x * x * x;
|
| 248 |
case 4: |
| 249 |
return boost::math::pow<4>(x); |
| 250 |
case 5: |
| 251 |
return boost::math::pow<5>(x); |
| 252 |
case 6: |
| 253 |
return boost::math::pow<6>(x); |
| 254 |
case 7: |
| 255 |
return boost::math::pow<7>(x); |
| 256 |
case 8: |
| 257 |
return boost::math::pow<8>(x); |
| 258 |
} |
| 259 |
BOOST_MATH_STD_USING |
| 260 |
#ifdef __SUNPRO_CC
|
| 261 |
return pow(x, T(ex));
|
| 262 |
#else
|
| 263 |
return pow(x, ex);
|
| 264 |
#endif
|
| 265 |
} |
| 266 |
template <class T> |
| 267 |
struct hypergeometric_pdf_prime_loop_result_entry
|
| 268 |
{
|
| 269 |
T value; |
| 270 |
const hypergeometric_pdf_prime_loop_result_entry* next;
|
| 271 |
}; |
| 272 |
|
| 273 |
#ifdef BOOST_MSVC
|
| 274 |
#pragma warning(push)
|
| 275 |
#pragma warning(disable:4510 4512 4610) |
| 276 |
#endif
|
| 277 |
|
| 278 |
struct hypergeometric_pdf_prime_loop_data
|
| 279 |
{
|
| 280 |
const unsigned x; |
| 281 |
const unsigned r; |
| 282 |
const unsigned n; |
| 283 |
const unsigned N; |
| 284 |
unsigned prime_index;
|
| 285 |
unsigned current_prime;
|
| 286 |
}; |
| 287 |
|
| 288 |
#ifdef BOOST_MSVC
|
| 289 |
#pragma warning(pop)
|
| 290 |
#endif
|
| 291 |
|
| 292 |
template <class T> |
| 293 |
T hypergeometric_pdf_prime_loop_imp(hypergeometric_pdf_prime_loop_data& data, hypergeometric_pdf_prime_loop_result_entry<T>& result) |
| 294 |
{
|
| 295 |
while(data.current_prime <= data.N)
|
| 296 |
{
|
| 297 |
unsigned base = data.current_prime;
|
| 298 |
int prime_powers = 0; |
| 299 |
while(base <= data.N)
|
| 300 |
{
|
| 301 |
prime_powers += data.n / base; |
| 302 |
prime_powers += data.r / base; |
| 303 |
prime_powers += (data.N - data.n) / base; |
| 304 |
prime_powers += (data.N - data.r) / base; |
| 305 |
prime_powers -= data.N / base; |
| 306 |
prime_powers -= data.x / base; |
| 307 |
prime_powers -= (data.n - data.x) / base; |
| 308 |
prime_powers -= (data.r - data.x) / base; |
| 309 |
prime_powers -= (data.N - data.n - data.r + data.x) / base; |
| 310 |
base *= data.current_prime; |
| 311 |
} |
| 312 |
if(prime_powers)
|
| 313 |
{
|
| 314 |
T p = integer_power<T>(static_cast<T>(data.current_prime), prime_powers);
|
| 315 |
if((p > 1) && (tools::max_value<T>() / p < result.value)) |
| 316 |
{
|
| 317 |
//
|
| 318 |
// The next calculation would overflow, use recursion
|
| 319 |
// to sidestep the issue:
|
| 320 |
//
|
| 321 |
hypergeometric_pdf_prime_loop_result_entry<T> t = { p, &result };
|
| 322 |
data.current_prime = prime(++data.prime_index); |
| 323 |
return hypergeometric_pdf_prime_loop_imp<T>(data, t);
|
| 324 |
} |
| 325 |
if((p < 1) && (tools::min_value<T>() / p > result.value)) |
| 326 |
{
|
| 327 |
//
|
| 328 |
// The next calculation would underflow, use recursion
|
| 329 |
// to sidestep the issue:
|
| 330 |
//
|
| 331 |
hypergeometric_pdf_prime_loop_result_entry<T> t = { p, &result };
|
| 332 |
data.current_prime = prime(++data.prime_index); |
| 333 |
return hypergeometric_pdf_prime_loop_imp<T>(data, t);
|
| 334 |
} |
| 335 |
result.value *= p; |
| 336 |
} |
| 337 |
data.current_prime = prime(++data.prime_index); |
| 338 |
} |
| 339 |
//
|
| 340 |
// When we get to here we have run out of prime factors,
|
| 341 |
// the overall result is the product of all the partial
|
| 342 |
// results we have accumulated on the stack so far, these
|
| 343 |
// are in a linked list starting with "data.head" and ending
|
| 344 |
// with "result".
|
| 345 |
//
|
| 346 |
// All that remains is to multiply them together, taking
|
| 347 |
// care not to overflow or underflow.
|
| 348 |
//
|
| 349 |
// Enumerate partial results >= 1 in variable i
|
| 350 |
// and partial results < 1 in variable j:
|
| 351 |
//
|
| 352 |
hypergeometric_pdf_prime_loop_result_entry<T> const *i, *j;
|
| 353 |
i = &result; |
| 354 |
while(i && i->value < 1) |
| 355 |
i = i->next; |
| 356 |
j = &result; |
| 357 |
while(j && j->value >= 1) |
| 358 |
j = j->next; |
| 359 |
|
| 360 |
T prod = 1;
|
| 361 |
|
| 362 |
while(i || j)
|
| 363 |
{
|
| 364 |
while(i && ((prod <= 1) || (j == 0))) |
| 365 |
{
|
| 366 |
prod *= i->value; |
| 367 |
i = i->next; |
| 368 |
while(i && i->value < 1) |
| 369 |
i = i->next; |
| 370 |
} |
| 371 |
while(j && ((prod >= 1) || (i == 0))) |
| 372 |
{
|
| 373 |
prod *= j->value; |
| 374 |
j = j->next; |
| 375 |
while(j && j->value >= 1) |
| 376 |
j = j->next; |
| 377 |
} |
| 378 |
} |
| 379 |
|
| 380 |
return prod;
|
| 381 |
} |
| 382 |
|
| 383 |
template <class T, class Policy> |
| 384 |
inline T hypergeometric_pdf_prime_imp(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&) |
| 385 |
{
|
| 386 |
hypergeometric_pdf_prime_loop_result_entry<T> result = { 1, 0 };
|
| 387 |
hypergeometric_pdf_prime_loop_data data = { x, r, n, N, 0, prime(0) };
|
| 388 |
return hypergeometric_pdf_prime_loop_imp<T>(data, result);
|
| 389 |
} |
| 390 |
|
| 391 |
template <class T, class Policy> |
| 392 |
T hypergeometric_pdf_factorial_imp(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&) |
| 393 |
{
|
| 394 |
BOOST_MATH_STD_USING |
| 395 |
BOOST_ASSERT(N <= boost::math::max_factorial<T>::value); |
| 396 |
T result = boost::math::unchecked_factorial<T>(n); |
| 397 |
T num[3] = {
|
| 398 |
boost::math::unchecked_factorial<T>(r), |
| 399 |
boost::math::unchecked_factorial<T>(N - n), |
| 400 |
boost::math::unchecked_factorial<T>(N - r) |
| 401 |
}; |
| 402 |
T denom[5] = {
|
| 403 |
boost::math::unchecked_factorial<T>(N), |
| 404 |
boost::math::unchecked_factorial<T>(x), |
| 405 |
boost::math::unchecked_factorial<T>(n - x), |
| 406 |
boost::math::unchecked_factorial<T>(r - x), |
| 407 |
boost::math::unchecked_factorial<T>(N - n - r + x) |
| 408 |
}; |
| 409 |
int i = 0; |
| 410 |
int j = 0; |
| 411 |
while((i < 3) || (j < 5)) |
| 412 |
{
|
| 413 |
while((j < 5) && ((result >= 1) || (i >= 3))) |
| 414 |
{
|
| 415 |
result /= denom[j]; |
| 416 |
++j; |
| 417 |
} |
| 418 |
while((i < 3) && ((result <= 1) || (j >= 5))) |
| 419 |
{
|
| 420 |
result *= num[i]; |
| 421 |
++i; |
| 422 |
} |
| 423 |
} |
| 424 |
return result;
|
| 425 |
} |
| 426 |
|
| 427 |
|
| 428 |
template <class T, class Policy> |
| 429 |
inline typename tools::promote_args<T>::type |
| 430 |
hypergeometric_pdf(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&) |
| 431 |
{
|
| 432 |
BOOST_FPU_EXCEPTION_GUARD |
| 433 |
typedef typename tools::promote_args<T>::type result_type; |
| 434 |
typedef typename policies::evaluation<result_type, Policy>::type value_type; |
| 435 |
typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type; |
| 436 |
typedef typename policies::normalise< |
| 437 |
Policy, |
| 438 |
policies::promote_float<false>,
|
| 439 |
policies::promote_double<false>,
|
| 440 |
policies::discrete_quantile<>, |
| 441 |
policies::assert_undefined<> >::type forwarding_policy; |
| 442 |
|
| 443 |
value_type result; |
| 444 |
if(N <= boost::math::max_factorial<value_type>::value)
|
| 445 |
{
|
| 446 |
//
|
| 447 |
// If N is small enough then we can evaluate the PDF via the factorials
|
| 448 |
// directly: table lookup of the factorials gives the best performance
|
| 449 |
// of the methods available:
|
| 450 |
//
|
| 451 |
result = detail::hypergeometric_pdf_factorial_imp<value_type>(x, r, n, N, forwarding_policy()); |
| 452 |
} |
| 453 |
else if(N <= boost::math::prime(boost::math::max_prime - 1)) |
| 454 |
{
|
| 455 |
//
|
| 456 |
// If N is no larger than the largest prime number in our lookup table
|
| 457 |
// (104729) then we can use prime factorisation to evaluate the PDF,
|
| 458 |
// this is slow but accurate:
|
| 459 |
//
|
| 460 |
result = detail::hypergeometric_pdf_prime_imp<value_type>(x, r, n, N, forwarding_policy()); |
| 461 |
} |
| 462 |
else
|
| 463 |
{
|
| 464 |
//
|
| 465 |
// Catch all case - use the lanczos approximation - where available -
|
| 466 |
// to evaluate the ratio of factorials. This is reasonably fast
|
| 467 |
// (almost as quick as using logarithmic evaluation in terms of lgamma)
|
| 468 |
// but only a few digits better in accuracy than using lgamma:
|
| 469 |
//
|
| 470 |
result = detail::hypergeometric_pdf_lanczos_imp(value_type(), x, r, n, N, evaluation_type(), forwarding_policy()); |
| 471 |
} |
| 472 |
|
| 473 |
if(result > 1) |
| 474 |
{
|
| 475 |
result = 1;
|
| 476 |
} |
| 477 |
if(result < 0) |
| 478 |
{
|
| 479 |
result = 0;
|
| 480 |
} |
| 481 |
|
| 482 |
return policies::checked_narrowing_cast<result_type, forwarding_policy>(result, "boost::math::hypergeometric_pdf<%1%>(%1%,%1%,%1%,%1%)"); |
| 483 |
} |
| 484 |
|
| 485 |
}}} // namespaces
|
| 486 |
|
| 487 |
#endif
|
| 488 |
|