43double betaCF(
double a,
double b,
double x)
45 const double FPMIN = 1e-300;
46 const double qab = a + b, qap = a + 1.0, qam = a - 1.0;
48 double d = 1.0 - qab * x / qap;
49 if (std::fabs(d) < FPMIN) d = FPMIN;
52 for (
int m = 1; m <= 500; ++m) {
53 const double m2 = 2.0 * m;
54 double aa = m * (b - m) * x / ((qam + m2) * (a + m2));
56 if (std::fabs(d) < FPMIN) d = FPMIN;
58 if (std::fabs(c) < FPMIN) c = FPMIN;
61 aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
63 if (std::fabs(d) < FPMIN) d = FPMIN;
65 if (std::fabs(c) < FPMIN) c = FPMIN;
67 const double del = d * c;
69 if (std::fabs(del - 1.0) < 1e-15)
return h;
74double betaI(
double a,
double b,
double x)
76 if (!(a > 0.0) || !(b > 0.0) || std::isnan(x))
return kNaN;
77 if (x <= 0.0)
return 0.0;
78 if (x >= 1.0)
return 1.0;
80 std::lgamma(a) + std::lgamma(b) - std::lgamma(a + b);
82 std::exp(a * std::log(x) + b * std::log(1.0 - x) -
lbeta);
84 if (x < (a + 1.0) / (a + b + 2.0))
85 result = front * betaCF(a, b, x) / a;
87 result = 1.0 - front * betaCF(b, a, 1.0 - x) / b;
95 const DistributionFamily &family()
const override;
96 double mean()
const override {
return p1_ / (p1_ + p2_); }
97 double variance()
const override {
98 const double s = p1_ + p2_;
99 return p1_ * p2_ / (s * s * (s + 1.0));
101 double rawMoment(
unsigned k)
const override {
102 if (k == 0)
return 1.0;
105 for (
unsigned i = 0; i < k; ++i)
106 r *= (p1_ +
static_cast<double>(i))
107 / (p1_ + p2_ +
static_cast<double>(i));
110 double pdf(
double c)
const override {
111 const double a = p1_, b = p2_;
112 if (!(a > 0.0) || !(b > 0.0))
return kNaN;
113 if (c < 0.0 || c > 1.0)
return 0.0;
118 if (a < 1.0)
return kNaN;
119 return (a == 1.0) ? b : 0.0;
122 if (b < 1.0)
return kNaN;
123 return (b == 1.0) ? a : 0.0;
126 std::lgamma(a) + std::lgamma(b) - std::lgamma(a + b);
127 return std::exp((a - 1.0) * std::log(c)
128 + (b - 1.0) * std::log(1.0 - c) -
lbeta);
130 double cdf(
double c)
const override {
131 return betaI(p1_, p2_, c);
133 DistSupport support()
const override {
return {0.0, 1.0}; }
134 bool integrationRange(
double &lo,
double &hi)
const override {
135 if (!(p1_ > 0.0 && p2_ > 0.0))
return false;
140 std::pair<double, double> plotRange(
double trunc_lo,
double trunc_hi)
const override {
141 double lo = trunc_lo, hi = trunc_hi;
142 if (!std::isfinite(lo)) lo = 0.0;
143 if (!std::isfinite(hi)) hi = 1.0;
144 return {std::max(lo, 0.0), std::min(hi, 1.0)};
146 double sample(std::mt19937_64 &rng)
const override {
149 std::gamma_distribution<double> ga(p1_, 1.0);
150 std::gamma_distribution<double> gb(p2_, 1.0);
151 const double x = ga(rng);
152 const double y = gb(rng);
155 std::optional<double> truncatedRawMoment(
double lo,
double hi,
156 unsigned k)
const override {
157 const double a = p1_, b = p2_;
158 if (!(a > 0.0) || !(b > 0.0))
return std::nullopt;
161 const double x_lo = std::isfinite(lo) ? std::max(lo, 0.0) : 0.0;
162 const double x_hi = std::isfinite(hi) ? std::min(hi, 1.0) : 1.0;
163 const double mass = betaI(a, b, x_hi) - betaI(a, b, x_lo);
164 if (std::isnan(mass) || mass < 1e-12)
return std::nullopt;
165 if (k == 0)
return 1.0;
166 const double kd =
static_cast<double>(k);
167 const double ratio = std::exp(
168 std::lgamma(a + kd) + std::lgamma(a + b)
169 - std::lgamma(a) - std::lgamma(a + b + kd));
170 const double shifted =
171 betaI(a + kd, b, x_hi) - betaI(a + kd, b, x_lo);
172 if (std::isnan(shifted))
return std::nullopt;
173 return ratio * shifted / mass;
175 std::string serialise()
const override {
178 std::unique_ptr<Distribution> affine(
double a,
double b)
const override {
187 "beta", 2,
"Β", {
"α",
"β"},
188 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
189 return std::make_unique<BetaDistribution>(p1, p2);
197[[maybe_unused]]
const DistributionFamilyRegistrar beta_family_registrar(
Internal helpers shared by the per-family Distribution implementations under src/distributions/.
Base holding the two parameters; subclasses add closed forms.
BaseDistribution(double p1, double p2)
double lbeta(double a, double b)
ln B(a, b) = lnΓ(a) + lnΓ(b) − lnΓ(a+b), for a, b > 0.
std::string double_to_text(double v)
Format a double back into the canonical text form used by gate_value extras and gate_rv distribution ...
A registered family's descriptor: its complete identity.