24inline constexpr double pi = 3.14159265358979323846;
29inline constexpr double sqrt_2 = 1.41421356237309504880;
34inline constexpr double sqrt_2_pi = 2.50662827463100050242;
59 if (x <= 0.0 && x == std::floor(x)) {
60 throw std::domain_error(
"statcpp::lgamma: non-positive integer argument");
64 static const double c[9] = {
72 9.9843695780195716e-6,
83 for (
int i = 1; i < 9; ++i) {
84 a += c[i] / (x +
static_cast<double>(i));
88 return log_sqrt_2_pi + (x + 0.5) * std::log(t) - t + std::log(a);
118 if (x <= 0.0 && x == std::floor(x)) {
119 throw std::domain_error(
"statcpp::tgamma: non-positive integer argument");
123 if (x > 0.0 && x <= 20.0 && x == std::floor(x)) {
125 for (
int i = 2; i < static_cast<int>(x); ++i) {
148inline double beta(
double a,
double b)
150 if (a <= 0.0 || b <= 0.0) {
151 throw std::domain_error(
"statcpp::beta: parameters must be positive");
166inline double lbeta(
double a,
double b)
168 if (a <= 0.0 || b <= 0.0) {
169 throw std::domain_error(
"statcpp::lbeta: parameters must be positive");
189inline double betainc_impl(
double a,
double b,
double x,
int recursion_depth)
195 if (recursion_depth > 1) {
196 throw std::runtime_error(
"statcpp::betainc: maximum recursion depth exceeded");
201 if (x > (a + 1.0) / (a + b + 2.0)) {
202 return 1.0 -
betainc_impl(b, a, 1.0 - x, recursion_depth + 1);
206 const double eps = std::numeric_limits<double>::epsilon();
207 const double tiny = std::numeric_limits<double>::min();
208 const int max_iter = 200;
211 double qap = a + 1.0;
212 double qam = a - 1.0;
215 double d = 1.0 - qab * x / qap;
216 if (std::abs(d) < tiny) d = tiny;
220 for (
int m = 1; m <= max_iter; ++m) {
224 double aa = m * (b - m) * x / ((qam + m2) * (a + m2));
226 if (std::abs(d) < tiny) d = tiny;
228 if (std::abs(c) < tiny) c = tiny;
233 aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
235 if (std::abs(d) < tiny) d = tiny;
237 if (std::abs(c) < tiny) c = tiny;
242 if (std::abs(del - 1.0) < eps) {
247 double front = std::exp(a * std::log(x) + b * std::log(1.0 - x) -
lbeta(a, b)) / a;
264inline double betainc(
double a,
double b,
double x)
266 if (a <= 0.0 || b <= 0.0) {
267 throw std::domain_error(
"statcpp::betainc: parameters must be positive");
269 if (x < 0.0 || x > 1.0) {
270 throw std::domain_error(
"statcpp::betainc: x must be in [0, 1]");
272 if (x == 0.0)
return 0.0;
273 if (x == 1.0)
return 1.0;
293 if (a <= 0.0 || b <= 0.0) {
294 throw std::domain_error(
"statcpp::betaincinv: parameters must be positive");
296 if (p < 0.0 || p > 1.0) {
297 throw std::domain_error(
"statcpp::betaincinv: p must be in [0, 1]");
299 if (p == 0.0)
return 0.0;
300 if (p == 1.0)
return 1.0;
302 const double eps = 1e-10;
303 const int max_iter = 100;
306 double x = a / (a + b);
307 if (a < 1.0 || b < 1.0) {
312 double lo = 0.0, hi = 1.0;
314 for (
int i = 0; i < max_iter; ++i) {
315 double f =
betainc(a, b, x) - p;
317 if (std::abs(f) < eps) {
329 double df = std::exp((a - 1.0) * std::log(x) + (b - 1.0) * std::log(1.0 - x) -
lbeta(a, b));
332 double x_new = x - dx;
335 if (x_new <= lo || x_new >= hi) {
336 x_new = (lo + hi) / 2.0;
339 if (std::abs(x_new - x) < eps * x) {
364inline double erf(
double x)
413 return -std::numeric_limits<double>::infinity();
416 return std::numeric_limits<double>::infinity();
420 static const double a[6] = {
421 -3.969683028665376e+01,
422 2.209460984245205e+02,
423 -2.759285104469687e+02,
424 1.383577518672690e+02,
425 -3.066479806614716e+01,
426 2.506628277459239e+00
428 static const double b[5] = {
429 -5.447609879822406e+01,
430 1.615858368580409e+02,
431 -1.556989798598866e+02,
432 6.680131188771972e+01,
433 -1.328068155288572e+01
435 static const double c[6] = {
436 -7.784894002430293e-03,
437 -3.223964580411365e-01,
438 -2.400758277161838e+00,
439 -2.549732539343734e+00,
440 4.374664141464968e+00,
441 2.938163982698783e+00
443 static const double d[4] = {
444 7.784695709041462e-03,
445 3.224671290700398e-01,
446 2.445134137142996e+00,
447 3.754408661907416e+00
450 const double p_low = 0.02425;
451 const double p_high = 1.0 - p_low;
457 q = std::sqrt(-2.0 * std::log(p));
458 return (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
459 ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1.0);
460 }
else if (p <= p_high) {
464 return (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q /
465 (((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1.0);
468 q = std::sqrt(-2.0 * std::log(1.0 - p));
469 return -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
470 ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1.0);
493 throw std::domain_error(
"statcpp::gammainc_lower: a must be positive");
496 throw std::domain_error(
"statcpp::gammainc_lower: x must be non-negative");
498 if (x == 0.0)
return 0.0;
500 const double eps = std::numeric_limits<double>::epsilon();
501 const int max_iter = 200;
505 double term = 1.0 / a;
507 for (
int n = 1; n <= max_iter; ++n) {
510 if (std::abs(term) < eps * std::abs(
sum)) {
514 return sum * std::exp(-x + a * std::log(x) -
lgamma(a));
518 const double tiny = std::numeric_limits<double>::min();
520 double b = x + 1.0 - a;
521 double c = 1.0 / tiny;
525 for (
int i = 1; i <= max_iter; ++i) {
526 double an = -i * (i - a);
529 if (std::abs(d) < tiny) d = tiny;
531 if (std::abs(c) < tiny) c = tiny;
535 if (std::abs(del - 1.0) < eps) {
541 double q = std::exp(-x + a * std::log(x) -
lgamma(a)) * h;
576 throw std::domain_error(
"statcpp::gammainc_lower_inv: a must be positive");
578 if (p < 0.0 || p > 1.0) {
579 throw std::domain_error(
"statcpp::gammainc_lower_inv: p must be in [0, 1]");
581 if (p == 0.0)
return 0.0;
582 if (p == 1.0)
return std::numeric_limits<double>::infinity();
584 const double eps = 1e-10;
585 const int max_iter = 100;
592 double v = t * std::sqrt(1.0 / (9.0 * a)) + 1.0 - 1.0 / (9.0 * a);
594 if (x <= 0.0) x = 0.5;
596 x = std::pow(p *
tgamma(a + 1.0), 1.0 / a);
601 double hi = a + 50.0 * std::sqrt(a);
602 if (hi < 10.0) hi = 10.0;
609 bool converged =
false;
612 for (
int i = 0; i < max_iter; ++i) {
614 if (std::abs(f) < eps) {
627 double df = std::exp((a - 1.0) * std::log(x) - x -
lgamma(a));
633 double x_new = x - f / df;
636 if (x_new <= lo || x_new >= hi) {
637 x_new = (lo + hi) / 2.0;
640 if (std::abs(x_new - x) < eps * x) {
651 for (
int bisect_iter = 0; bisect_iter < 100; ++bisect_iter) {
652 double mid = (lo + hi) / 2.0;
654 if (std::abs(f_mid) < 1e-12 || (hi - lo) < 1e-12 * mid) {
663 return (lo + hi) / 2.0;
double betainc(double a, double b, double x)
Regularized incomplete beta function.
double lbeta(double a, double b)
Log-beta function.
double tgamma(double x)
Gamma function.
double erf(double x)
Error function.
constexpr double pi
Pi constant.
double lgamma_impl(double x)
Internal log-gamma function implementation.
auto sum(Iterator first, Iterator last)
Sum.
double norm_cdf(double x)
Standard normal CDF.
double erfc(double x)
Complementary error function.
double norm_quantile(double p)
Standard normal quantile function.
constexpr double sqrt_2
Square root of 2.
constexpr double sqrt_2_pi
Square root of 2*pi.
double gammainc_lower_inv(double a, double p)
Inverse lower regularized incomplete gamma function.
double betainc_impl(double a, double b, double x, int recursion_depth)
Internal regularized incomplete beta function.
double beta(double a, double b)
Beta function.
double betaincinv(double a, double b, double p)
Inverse regularized incomplete beta function.
double gammainc_lower(double a, double x)
Lower regularized incomplete gamma function.
constexpr double log_sqrt_2_pi
Natural logarithm of sqrt(2*pi)
double gammainc_upper(double a, double x)
Upper regularized incomplete gamma function.
double lgamma(double x)
Log-gamma function.