3#define SPECIAL_FUNCTION_MAX_ITERATIONS 1000
4#define SPECIAL_FUNCTION_TOLERANCE 1e-15
5#define LENTZ_TINY 1e-300
9 return copysign(
LENTZ_TINY, value == 0.0 ? 1.0 : value);
16 return lgamma(x + 1.0) -
17 (x + 0.5) * log(x) + x -
23 const lmmc_real_t inverse_squared = inverse * inverse;
30 inverse_squared / 1680.0)));
38 (x - 0.5) * log(x) + x -
44 const lmmc_real_t inverse_squared = inverse * inverse;
51 inverse_squared / 1680.0)));
56 if (x == mean) {
return 0.0; }
57 if (x == 0.0) {
return mean; }
58 if (mean == 0.0) {
return INFINITY; }
60 if (fabs(x - mean) < 0.1 * x + 0.1 * mean) {
63 const lmmc_real_t ratio = (difference / x) / (1.0 + mean / x);
69 for (order = 1; order < 100; ++order) {
71 term *= ratio_squared;
73 if (sum == previous) {
break; }
81 quotient > 0.0 && isfinite(quotient) ? log(quotient) :
84 x * (log_ratio - 1.0) + mean :
85 x * log_ratio + mean - x;
102static int regularized_gamma_large_central_upper(
104 lmmc_real_t delta, eta, eta_squared, c0, correction, value;
106 if (a < 10000.0 || x <= 0.0) {
return 0; }
108 if (fabs(delta) > 0.1) {
return 0; }
110 eta_squared = 2.0 * (delta - log1p(delta));
111 if (eta_squared < 0.0) {
112 if (eta_squared > -DBL_EPSILON) {
118 eta = copysign(sqrt(eta_squared), delta);
119 if (fabs(eta) * sqrt(a) > 8.0) {
return 0; }
121 if (fabs(eta) < 1e-3) {
122 c0 = -1.0 / 3.0 + eta / 12.0 -
123 2.0 * eta * eta / 135.0;
125 c0 = 1.0 / delta - 1.0 / eta;
128 exp(-0.5 * a * eta_squared) * c0 /
130 value = 0.5 * erfc(eta * sqrt(0.5 * a)) + correction;
131 if (!isfinite(value) || value < 0.0 || value > 1.0) {
return 0; }
144 if (x <= 0.0) {
return store_regularized_probability(0.0, out); }
147 if (regularized_gamma_large_central_upper(a, x, &upper)) {
return store_regularized_probability(1.0 - upper, out); }
162 return store_regularized_probability(
163 sum * exp(-x + a * log(x) - lgamma(a)), out);
168 return store_regularized_probability(1.0 - upper, out);
184 f = lentz_nonzero(f);
194 d = lentz_nonzero(d);
197 c = lentz_nonzero(c);
204 return store_regularized_probability(
205 exp(-x + a * log(x) - lgamma(a)) / f, out);
214 if (x <= 0.0) {
return store_regularized_probability(1.0, out); }
217 if (regularized_gamma_large_central_upper(a, x, &upper)) {
return store_regularized_probability(upper, out); }
223 return store_regularized_probability(1.0 - lower, out);
241 d = complement_x + (1.0 - b) * x / qap;
242 d = lentz_nonzero(d);
250 ((b - order) * x / (a + m2)) * (order / (qam + m2));
257 (a / (a + m2)) * ((1.0 + m2 - b) * x / (qap + m2)) +
259 ((2.0 + 3.0 * order - b) * x / (qap + m2));
263 lmmc_real_t d_denominator = one_plus_odd + d_offset;
268 c_numerator = lentz_nonzero(c_numerator);
269 d_denominator = lentz_nonzero(d_denominator);
270 c_denominator = lentz_nonzero(c_denominator);
271 d_numerator = lentz_nonzero(d_numerator);
272 c = c_numerator / c_denominator;
273 d = d_numerator / d_denominator;
274 delta = c_numerator / d_denominator;
276 if (!isfinite(even) || !isfinite(one_plus_odd)) {
279 if (!isfinite(c) || !isfinite(d)) {
282 if (!isfinite(delta) || !isfinite(f)) {
296static double beta_stirling_inverse(
double inverse) {
297 const double square = inverse * inverse;
298 return inverse * (1.0 / 12.0 + square * (-1.0 / 360.0 +
299 square * (1.0 / 1260.0 - square / 1680.0)));
306static double beta_scaled_log1pmx(
double small,
double large) {
307 const double ratio = small / large;
308 if (ratio <= 0.125) {
309 double polynomial = -1.0 / 32.0;
311 for (k = 31; k >= 2; --k) {
312 polynomial = fma(polynomial, ratio,
313 (k % 2 ? 1.0 : -1.0) / (
double)k);
315 return (small * ratio) * polynomial;
317 return large * (log1p(ratio) - ratio);
320static double beta_ratio_correction(
double small,
double large) {
321 const double ratio = small / large;
322 return (small - 0.5) * log1p(ratio) +
323 beta_scaled_log1pmx(small, large) +
324 beta_stirling_inverse((1.0 / large) / (1.0 + ratio)) -
330 const double small = fmin(a, b), large = fmax(a, b);
331 if (!out_log_beta || !isfinite(a) || !isfinite(b) || a <= 0.0 || b <= 0.0) {
335 value = lgamma(small) + lgamma(large) - lgamma(small + large);
336 }
else if (small < 16.0) {
337 value = lgamma(small) -
338 (small * log(large) + beta_ratio_correction(small, large));
340 const double ratio = small / large;
341 const double logarithm = log1p(ratio);
342 const double log_ratio = ratio > 0.0
343 ? log(ratio) : log(small) - log(large);
344 value = small * (log_ratio - logarithm) - large * logarithm +
348 beta_stirling_inverse((1.0 / large) / (1.0 + ratio));
351 *out_log_beta = value;
355static int beta_log_kernel_arguments_valid(
356 double x,
double complement_x,
double a,
double b,
const double* out_log_kernel) {
357 if (!out_log_kernel || !isfinite(a) || !isfinite(b) || a <= 0.0 || b <= 0.0) {
360 if (!isfinite(x) || !isfinite(complement_x)) {
363 if (x <= 0.0 || x > 1.0 || complement_x <= 0.0 || complement_x > 1.0) {
370 double x,
double complement_x,
double a,
double b,
double total,
double* value) {
371 if (isfinite(total)) {
378 }
else if (a == b && x == 0.5 && complement_x == 0.5) {
379 *value = 0.5 * (log(a) - log(
LMMC_PI)) - log(2.0) -
387static double beta_log_kernel_one_large_shape(
388 double x,
double complement_x,
double a,
double b,
389 double log_x,
double log_complement) {
390 const double small = fmin(a, b), large = fmax(a, b);
391 const double small_x = a < b ? x : complement_x;
392 const double log_small_x = a < b ? log_x : log_complement;
393 const double log_large_x = a < b ? log_complement : log_x;
394 const double product = small_x * large;
395 const double log_product = product > 0.0
396 ? log(product) : log_small_x + log(large);
397 return small * log_product + large * log_large_x - lgamma(small) +
398 beta_ratio_correction(small, large);
402 double x,
double complement_x,
double a,
double b,
double* out_log_kernel) {
403 const double total = a + b;
405 double log_x, log_complement;
406 if (!beta_log_kernel_arguments_valid(x, complement_x, a, b, out_log_kernel)) {
409 log_x = x <= 0.5 ? log(x) : log1p(-complement_x);
410 log_complement = complement_x <= 0.5 ? log(complement_x) : log1p(-x);
411 if (a >= 16.0 && b >= 16.0) {
413 beta_log_kernel_large_shapes(x, complement_x, a, b, total, &value);
415 }
else if (a >= 16.0 || b >= 16.0) {
416 value = beta_log_kernel_one_large_shape(x, complement_x, a, b, log_x, log_complement);
421 value = a * log_x + b * log_complement - logarithm;
424 *out_log_kernel = value;
433 const int lower = x * (b + 1.0) < complement_x * (a + 1.0);
434 if (x == 0.5 && a == b) {
return store_regularized_probability(0.5, out); }
441 status = regularized_beta_cf(x, complement_x, a, b, &fraction);
444 status = regularized_beta_cf(complement_x, x, b, a, &fraction);
449 result = exp(log_bt + log(fraction) - log(shape));
451 return store_regularized_probability(lower ? result : 1.0 - result, out);
457 if (x <= 0.0) {
return store_regularized_probability(0.0, out); }
458 if (x >= 1.0) {
return store_regularized_probability(1.0, out); }
459 return regularized_beta_pair(x, 1.0 - x, a, b, out);
465 if (x <= 0.0) {
return store_regularized_probability(1.0, out); }
466 if (x >= 1.0) {
return store_regularized_probability(0.0, out); }
467 return regularized_beta_pair(1.0 - x, x, b, a, out);
double lmmc_real_t
Public and internal LMMC real type.
#define SPECIAL_FUNCTION_TOLERANCE
lmmc_status_t lmmc_log_beta(double a, double b, double *out_log_beta)
稳定计算 log B(a,b) 和 log(x^a complement_x^b / B(a,b))。 独立传入补数以保留微小上尾;负无穷表示有效下溢,失败时输出保持不变。
lmmc_real_t lmmc_stirling_error(lmmc_real_t x)
lmmc_status_t regularized_gamma_lower(lmmc_real_t a, lmmc_real_t x, lmmc_real_t *out)
正则化不完全伽马函数下尾 P(a, x) = gamma(a, x) / Gamma(a)。 使用级数展开或连分数展开。
lmmc_status_t regularized_gamma_upper_cf(lmmc_real_t a, lmmc_real_t x, lmmc_real_t *out)
正则化不完全伽马函数上尾 Q(a, x) = 1 - P(a, x)。 使用 Lentz 连分数展开。
lmmc_status_t regularized_beta(lmmc_real_t x, lmmc_real_t a, lmmc_real_t b, lmmc_real_t *out)
lmmc_status_t regularized_beta_upper(lmmc_real_t x, lmmc_real_t a, lmmc_real_t b, lmmc_real_t *out)
计算上尾;1 - x 舍入至端点时仍保留 x。
lmmc_real_t lmmc_log_gamma_stirling_error(lmmc_real_t x)
#define SPECIAL_FUNCTION_MAX_ITERATIONS
lmmc_status_t regularized_gamma_upper(lmmc_real_t a, lmmc_real_t x, lmmc_real_t *out)
正则化不完全伽马函数上尾 Q(a, x)。
lmmc_real_t lmmc_deviance_part(lmmc_real_t x, lmmc_real_t mean)
lmmc_status_t lmmc_beta_log_kernel(double x, double complement_x, double a, double b, double *out_log_kernel)
#define LMMC_LOG_SQRT_2PI
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_CONVERGENCE_FAILED
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_INVALID_ARGUMENT