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)
440 return -std::numeric_limits<double>::infinity();
443 return std::numeric_limits<double>::infinity();
447 static const double a[6] = {
448 -3.969683028665376e+01,
449 2.209460984245205e+02,
450 -2.759285104469687e+02,
451 1.383577518672690e+02,
452 -3.066479806614716e+01,
453 2.506628277459239e+00
455 static const double b[5] = {
456 -5.447609879822406e+01,
457 1.615858368580409e+02,
458 -1.556989798598866e+02,
459 6.680131188771972e+01,
460 -1.328068155288572e+01
462 static const double c[6] = {
463 -7.784894002430293e-03,
464 -3.223964580411365e-01,
465 -2.400758277161838e+00,
466 -2.549732539343734e+00,
467 4.374664141464968e+00,
468 2.938163982698783e+00
470 static const double d[4] = {
471 7.784695709041462e-03,
472 3.224671290700398e-01,
473 2.445134137142996e+00,
474 3.754408661907416e+00
477 const double p_low = 0.02425;
478 const double p_high = 1.0 - p_low;
484 q = std::sqrt(-2.0 * std::log(p));
485 return (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
486 ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1.0);
487 }
else if (p <= p_high) {
491 return (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q /
492 (((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1.0);
495 q = std::sqrt(-2.0 * std::log(1.0 - p));
496 return -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
497 ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1.0);
520 throw std::domain_error(
"statcpp::gammainc_lower: a must be positive");
523 throw std::domain_error(
"statcpp::gammainc_lower: x must be non-negative");
525 if (x == 0.0)
return 0.0;
527 const double eps = std::numeric_limits<double>::epsilon();
528 const int max_iter = 200;
532 double term = 1.0 / a;
534 for (
int n = 1; n <= max_iter; ++n) {
537 if (std::abs(term) < eps * std::abs(
sum)) {
541 return sum * std::exp(-x + a * std::log(x) -
lgamma(a));
545 const double tiny = std::numeric_limits<double>::min();
547 double b = x + 1.0 - a;
548 double c = 1.0 / tiny;
552 for (
int i = 1; i <= max_iter; ++i) {
553 double an = -i * (i - a);
556 if (std::abs(d) < tiny) d = tiny;
558 if (std::abs(c) < tiny) c = tiny;
562 if (std::abs(del - 1.0) < eps) {
568 double q = std::exp(-x + a * std::log(x) -
lgamma(a)) * h;
603 throw std::domain_error(
"statcpp::gammainc_lower_inv: a must be positive");
605 if (p < 0.0 || p > 1.0) {
606 throw std::domain_error(
"statcpp::gammainc_lower_inv: p must be in [0, 1]");
608 if (p == 0.0)
return 0.0;
609 if (p == 1.0)
return std::numeric_limits<double>::infinity();
611 const double eps = 1e-10;
612 const int max_iter = 100;
619 double v = t * std::sqrt(1.0 / (9.0 * a)) + 1.0 - 1.0 / (9.0 * a);
621 if (x <= 0.0) x = 0.5;
623 x = std::pow(p *
tgamma(a + 1.0), 1.0 / a);
628 double hi = a + 50.0 * std::sqrt(a);
629 if (hi < 10.0) hi = 10.0;
636 bool converged =
false;
639 for (
int i = 0; i < max_iter; ++i) {
641 if (std::abs(f) < eps) {
654 double df = std::exp((a - 1.0) * std::log(x) - x -
lgamma(a));
660 double x_new = x - f / df;
663 if (x_new <= lo || x_new >= hi) {
664 x_new = (lo + hi) / 2.0;
667 if (std::abs(x_new - x) < eps * x) {
678 for (
int bisect_iter = 0; bisect_iter < 100; ++bisect_iter) {
679 double mid = (lo + hi) / 2.0;
681 if (std::abs(f_mid) < 1e-12 || (hi - lo) < 1e-12 * mid) {
690 return (lo + hi) / 2.0;
double betainc(double a, double b, double x)
Regularized incomplete beta function.
double norm_sf(double x)
Standard normal survival 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.