22template <std::
floating_po
int Real>
23Real
logBeta(Real a, std::type_identity_t<Real> b);
25template <
typename Left,
typename Right>
26 requires(std::is_arithmetic_v<Left> && std::is_arithmetic_v<Right> &&
27 (std::integral<Left> || std::integral<Right> || !std::same_as<Left, Right>))
40template <std::
floating_po
int Real>
41Real
ibeta(Real x, std::type_identity_t<Real> a, std::type_identity_t<Real> b, std::type_identity_t<Real> logBetaFun,
42 std::type_identity_t<Real> logX, std::type_identity_t<Real> log1mX);
51template <std::
floating_po
int Real>
52Real
ibeta(Real x, std::type_identity_t<Real> a, std::type_identity_t<Real> b);
71template <std::
floating_po
int Real>
72inline Real
logBeta(Real a, std::type_identity_t<Real> b)
75 throw std::invalid_argument(
"Parameters (a, b) of beta function should be both positive");
77 using Work = std::conditional_t<(
sizeof(Real) <
sizeof(
long double)),
long double, Real>;
78 Work p = std::min(
static_cast<Work
>(a),
static_cast<Work
>(b));
79 Work q = std::max(
static_cast<Work
>(a),
static_cast<Work
>(b));
82 Work result = -Work{0.5} * std::log(q) +
84 (p - Work{0.5}) * std::log(p / (p + q)) + q * std::log1p(-p / (p + q));
85 return static_cast<Real
>(result);
89 Work result = std::lgamma(p) + corr + p - p * std::log(p + q) + (q - Work{0.5}) * std::log1p(-p / (p + q));
90 return static_cast<Real
>(result);
92 return static_cast<Real
>(std::log(std::tgamma(p) * (std::tgamma(q) / std::tgamma(p + q))));
95template <
typename Left,
typename Right>
96 requires(std::is_arithmetic_v<Left> && std::is_arithmetic_v<Right> &&
97 (std::integral<Left> || std::integral<Right> || !std::same_as<Left, Right>))
100 using Real = std::common_type_t<double, Left, Right>;
101 return logBeta(
static_cast<Real
>(a),
static_cast<Real
>(b));
104template <std::
floating_po
int Real>
107 Real addon = 1.0, sum = 0.0;
109 Real u = (x > 1e-5) ? -x / (1.0 - x) : -std::exp(logX - log1mX);
112 addon *= (n - b) * u / (a + n);
117 y += (b - 1) * log1mX;
119 y += std::log1p(sum);
120 return std::exp(y) / a;
123template <std::
floating_po
int Real>
128 Real u = (x > 1e-5) ? x / (1.0 - x) : std::exp(logX - log1mX);
131 Real cn = (b - n + 1) / (a + n - 1) * u;
132 frac = cn / (1 + cn - frac);
136 Real F = c1 / (1 + c1 - frac);
138 y += (b - 1) * log1mX;
145template <std::
floating_po
int Real>
148 Real addon = 1.0, sum = 0.0;
151 addon *= (n + a + b) * x / (a + n + 1);
158 y += std::log1p(sum);
159 return std::exp(y) / a;
162template <std::
floating_po
int Real>
168 Real cn = (a + b + n - 2) / (a + n - 1) * x;
169 frac = cn / (1 + cn - frac);
172 Real c1 = (a + b - 1) / a;
173 Real F = c1 / (1 + c1 - frac);
177 y = std::exp(y) / (a + b - 1);
184template <std::
floating_po
int Real>
187 constexpr Real epsilon = std::numeric_limits<Real>::epsilon();
188 constexpr Real tiny = std::numeric_limits<Real>::min() / epsilon;
189 auto guard = [](Real value) {
return (std::fabs(value) < tiny) ? tiny : value; };
190 Real c = 1, d = 1 / guard(1 - (a + b) * x / (a + 1));
192 for (
int m = 1; m < 1000000; ++m) {
193 const Real even = m * (b - m) * x / ((a + 2 * m - 1) * (a + 2 * m));
194 d = 1 / guard(1 + even * d);
195 c = guard(1 + even / c);
197 const Real odd = -(a + m) * (a + b + m) * x / ((a + 2 * m) * (a + 2 * m + 1));
198 d = 1 / guard(1 + odd * d);
199 c = guard(1 + odd / c);
200 const Real step = d * c;
202 if (std::fabs(step - 1) <= epsilon)
205 return std::exp(a * logX + b * log1mX - logBetaFun) * fraction / a;
218template <std::
floating_po
int Real>
219inline Real
ibetaLowerTail(Real x, Real a, Real b, Real logBetaFun, Real logX, Real log1mX)
222 return std::exp(a * logX);
224 return -std::expm1(b * log1mX);
231 int number =
static_cast<int>(std::floor(b));
234 Real apn = a +
static_cast<Real
>(number), bmn = b -
static_cast<Real
>(number);
236 return ecd + residue;
241 int number =
static_cast<int>(std::floor(b));
244 Real apn = a +
static_cast<Real
>(number);
246 return ecd + residue;
249template <std::
floating_po
int Real>
250inline Real
ibeta(Real x, std::type_identity_t<Real> a, std::type_identity_t<Real> b,
251 std::type_identity_t<Real> logBetaFun, std::type_identity_t<Real> logX,
252 std::type_identity_t<Real> log1mX)
255 if (!(a > 0 && b > 0))
256 throw std::invalid_argument(
257 "Parameters (a, b) of incomplete beta function should be both positive, but they're equal to " +
258 std::to_string(a) +
" and " + std::to_string(b) +
" respectively");
259 if (!(x >= 0.0 && x <= 1.0))
260 throw std::invalid_argument(
261 "Argument x of incomplete beta function should be in interval [0, 1], but it's equal to " +
264 if (x == 0.0 || logX == -INFINITY)
266 if (log1mX == -INFINITY)
268 const Real y = (x < 0.5) ? Real{1} - x : std::exp(log1mX);
274 constexpr Real TINY_ARGUMENT = 1e-4, DEVIATIONS = 4;
275 const Real c = (a + 1) / (a + b + 2);
276 const bool directExtends = x < TINY_ARGUMENT && x < c * (1 + DEVIATIONS / std::sqrt(a + 1));
277 const bool complementExtends = y < TINY_ARGUMENT && y < (1 - c) * (1 + DEVIATIONS / std::sqrt(b + 1));
278 const bool direct = (x < c) ? !complementExtends : directExtends;
280 return ibetaContinuedFractionLentz<Real>(x, a, b, logBetaFun, logX, log1mX);
281 return Real{1} - ibetaContinuedFractionLentz<Real>(y, b, a, logBetaFun, log1mX, logX);
289 constexpr Real SLOW_SERIES_DISTANCE = 1e-3;
290 const bool complement = (x > a / (a + b)) ? x >= SLOW_SERIES_DISTANCE : y < SLOW_SERIES_DISTANCE;
292 return Real{1} - ibetaLowerTail<Real>(y, b, a, logBetaFun, log1mX, logX);
293 return ibetaLowerTail<Real>(x, a, b, logBetaFun, logX, log1mX);
296template <std::
floating_po
int Real>
297inline Real
ibeta(Real x, std::type_identity_t<Real> a, std::type_identity_t<Real> b)
300 if (a <= 0 || b <= 0 || x < 0.0 || x > 1.0)
301 throw std::invalid_argument(
"Parameters (a, b) of incomplete beta function should be both positive");
302 if (x < 0.0 || x > 1.0)
303 throw std::invalid_argument(
"Argument x of incomplete beta function should be in interval [0, 1]");
309 return std::pow(x, a);
311 Real y = b * std::log1p(-x);
312 return -std::expm1(y);
314 Real logBetaFun =
logBeta(a, b);
315 Real logX = std::log(x), log1mX = std::log1p(-x);
316 return ibeta(x, a, b, logBetaFun, logX, log1mX);
constexpr long double ln2
Definition constants.hpp:18
constexpr long double lnpi
Definition constants.hpp:21
constexpr double IBETA_LARGEST_FINITE_SHAPE
Beyond this size of a shape the finite continued fractions of ibetaLowerTail accumulate rounding erro...
Definition math/beta.hpp:213
constexpr long double minimumTolerance
Definition constants.hpp:44
Real ibetaLowerTail(Real x, Real a, Real b, Real logBetaFun, Real logX, Real log1mX)
I(x, a, b) for x not above the mean a / (a + b) and shapes up to IBETA_LARGEST_FINITE_SHAPE.
Definition math/beta.hpp:219
Real logBeta(Real a, std::type_identity_t< Real > b)
Calculate logarithm of beta function.
Definition math/beta.hpp:72
Real ibetacontinuedFraction1(Real x, Real a, Real b, int number, Real logBetaFun, Real logX, Real log1mX)
Definition math/beta.hpp:124
Real ibetaContinuedFractionLentz(Real x, Real a, Real b, Real logBetaFun, Real logX, Real log1mX)
Continued fraction of I(x, a, b) (DiDonato and Morris, also Numerical Recipes betacf) by the modified...
Definition math/beta.hpp:185
Real lgammaCorrection(Real x)
Definition special_functions.hpp:350
Real ibetaPowerSeries1(Real x, Real a, Real b, Real logBetaFun, Real logX, Real log1mX)
Definition math/beta.hpp:105
Real ibeta(Real x, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > logBetaFun, std::type_identity_t< Real > logX, std::type_identity_t< Real > log1mX)
Fast calculation of regularized beta function, using precalculated values.
Definition math/beta.hpp:250
Real ibetaPowerSeries2(Real x, Real a, Real b, Real logBetaFun, Real logX, Real log1mX)
Definition math/beta.hpp:146
Real ibetaContinuedFraction2(Real x, Real a, Real b, int number, Real logBetaFun, Real logX, Real log1mX)
Definition math/beta.hpp:163
Definition bivariate_normal.hpp:10