LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
probability_continuous.c
浏览该文件的文档.
1#include <math.h>
2#include <float.h>
3
4#include "lmmc/config.h"
5#include "lmmc/numeric.h"
6#include "lmmc/stats.h"
7
9
10static lmmc_real_t standardized_normal_value(
11 lmmc_real_t x, lmmc_real_t mu, lmmc_real_t sigma) {
12 const lmmc_real_t centered = x - mu;
13 if (isfinite(centered)) { return centered / sigma; }
14 return x / sigma - mu / sigma;
15}
16
18 lmmc_real_t sigma, lmmc_real_t* out) {
19 lmmc_real_t z, log_density;
20 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
21 if (!isfinite(x) || !isfinite(mu) || !valid_positive(sigma)) { return LMMC_STATUS_INVALID_ARGUMENT; }
22
23 z = standardized_normal_value(x, mu, sigma);
24 log_density =
25 -0.5 * z * z - log(sigma) - log(LMMC_SQRT_2PI);
26 return store_density_from_log(log_density, out);
27}
28
30 lmmc_real_t sigma, lmmc_real_t* out) {
32 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
33 if (!isfinite(x) || !isfinite(mu) || !valid_positive(sigma)) { return LMMC_STATUS_INVALID_ARGUMENT; }
34
35 z = standardized_normal_value(x, mu, sigma);
36 return store_probability_result(
37 0.5 * erfc(-z / sqrt(2.0)), out);
38}
39
40static lmmc_real_t student_t_log_kernel(
42 const lmmc_real_t abs_x = fabs(x);
43 const lmmc_real_t sqrt_df = sqrt(df);
44 if (abs_x <= sqrt_df) {
45 const lmmc_real_t ratio = abs_x / sqrt_df;
46 return log1p(ratio * ratio);
47 }
48 {
49 const lmmc_real_t ratio = sqrt_df / abs_x;
50 return 2.0 * log(abs_x) - log(df) +
51 log1p(ratio * ratio);
52 }
53}
54
55static lmmc_real_t student_t_beta_argument(
57 const lmmc_real_t abs_x = fabs(x);
58 const lmmc_real_t sqrt_df = sqrt(df);
59 if (abs_x <= sqrt_df) {
60 const lmmc_real_t ratio = abs_x / sqrt_df;
61 const lmmc_real_t ratio_sq = ratio * ratio;
62 return 1.0 / (1.0 + ratio_sq);
63 }
64 {
65 const lmmc_real_t ratio = sqrt_df / abs_x;
66 const lmmc_real_t ratio_sq = ratio * ratio;
67 return ratio_sq / (1.0 + ratio_sq);
68 }
69}
70
72 lmmc_real_t log_density;
73 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
74 if (!isfinite(x) || !valid_positive(df)) { return LMMC_STATUS_INVALID_ARGUMENT; }
75 if (student_t_uses_normal_limit(df)) {
76 return store_density_from_log(
77 -0.5 * x * x - LMMC_LOG_SQRT_2PI, out);
78 }
79 if (df / 2.0 == 0.0) {
80 /* B(df/2, 1/2) ~ 2/df as df tends to zero. */
81 log_density = 0.5 * log(df) - log(2.0) -
82 0.5 * student_t_log_kernel(x, df);
83 return store_density_from_log(log_density, out);
84 }
85
86 {
87 double log_beta;
88 const lmmc_status_t status = lmmc_log_beta(df / 2.0, 0.5, &log_beta);
89 if (status != LMMC_STATUS_OK) { return status; }
90 log_density = -log_beta - 0.5 * log(df) -
91 ((df + 1.0) / 2.0) * student_t_log_kernel(x, df);
92 }
93 return store_density_from_log(log_density, out);
94}
95
97 lmmc_real_t t_val, ib, result;
98 lmmc_status_t status;
99 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
100 if (!isfinite(x) || !valid_positive(df)) { return LMMC_STATUS_INVALID_ARGUMENT; }
101 if (student_t_uses_normal_limit(df)) {
102 return store_probability_result(
103 0.5 * erfc(-x / sqrt(2.0)), out);
104 }
105 if (df / 2.0 == 0.0) {
106 *out = 0.5;
107 return LMMC_STATUS_OK;
108 }
109
110 t_val = student_t_beta_argument(x, df);
111 if (t_val > 0.0) {
112 status = regularized_beta(t_val, df / 2.0, 0.5, &ib);
113 if (status != LMMC_STATUS_OK) { return status; }
114 } else {
115 const lmmc_real_t a = df / 2.0;
116 const lmmc_real_t log_t =
117 log(df) - 2.0 * log(fabs(x));
118 lmmc_real_t log_beta;
119 status = lmmc_log_beta(a, 0.5, &log_beta);
120 if (status != LMMC_STATUS_OK) { return status; }
121 ib = exp(a * log_t - log(a) - log_beta);
122 }
123 result = x >= 0.0 ? 1.0 - 0.5 * ib : 0.5 * ib;
124 return store_probability_result(result, out);
125}
126
128 lmmc_real_t k2;
129 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
130 if (!isfinite(x) || !valid_positive(df)) { return LMMC_STATUS_INVALID_ARGUMENT; }
131 if (x < 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
132 if (x == 0.0) {
133 if (df < 2.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
134 if (df == 2.0) { *out = 0.5; return LMMC_STATUS_OK; }
135 *out = 0.0; return LMMC_STATUS_OK;
136 }
137
138 if (df / 2.0 == 0.0) {
139 /* Gamma(df/2) ~ 2/df as df tends to zero. */
140 return store_density_from_log(
141 log(df) - log(x) - log(2.0) - x / 2.0, out);
142 }
143
144 k2 = df / 2.0;
145 if (k2 >= 16.0) {
146 return lmmc_dist_gamma_pdf(x, k2, 2.0, out);
147 }
148 return store_density_from_log(
149 (k2 - 1.0) * log(x) - x / 2.0 -
150 k2 * log(2.0) - lgamma(k2),
151 out);
152}
153
155 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
156 if (!isfinite(x) || !valid_positive(df)) { return LMMC_STATUS_INVALID_ARGUMENT; }
157 if (x <= 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
158 /* For a = df/2 below the smallest double, P(a, x/2) rounds to one. */
159 if (df / 2.0 == 0.0) { *out = 1.0; return LMMC_STATUS_OK; }
160
161 return lmmc_dist_gamma_cdf(x, df / 2.0, 2.0, out);
162}
163
164static int f_beta_density(
166 lmmc_real_t first_shape, lmmc_real_t second_shape,
167 lmmc_real_t* out, lmmc_status_t* status) {
168 const lmmc_real_t scale = df2 / df1;
169 if (isfinite(scale) && scale > 0.0) {
170 lmmc_real_t beta_x;
171 lmmc_real_t beta_complement;
172 if (x > scale) {
173 const lmmc_real_t ratio = scale / x;
174 beta_x = 1.0 / (1.0 + ratio);
175 beta_complement = ratio / (1.0 + ratio);
176 } else {
177 const lmmc_real_t ratio = x / scale;
178 beta_x = ratio / (1.0 + ratio);
179 beta_complement = 1.0 / (1.0 + ratio);
180 }
181 if (beta_x > 0.0 && beta_complement > 0.0) {
182 double log_kernel;
183 *status = lmmc_beta_log_kernel(
184 beta_x, beta_complement, first_shape, second_shape, &log_kernel);
185 if (*status == LMMC_STATUS_OK) {
186 *status = store_density_from_log(log_kernel - log(x), out);
187 }
188 return 1;
189 }
190 }
191 return 0;
192}
193
195 lmmc_real_t* out) {
196 lmmc_real_t first_shape, second_shape, total_shape;
197 lmmc_real_t num, den;
198 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
199 if (!isfinite(x) || !valid_positive(df1) || !valid_positive(df2)) { return LMMC_STATUS_INVALID_ARGUMENT; }
200 if (x < 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
201 if (x == 0.0) {
202 if (df1 < 2.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
203 if (df1 == 2.0) { *out = 1.0; return LMMC_STATUS_OK; }
204 *out = 0.0; return LMMC_STATUS_OK;
205 }
206
207 first_shape = df1 / 2.0;
208 second_shape = df2 / 2.0;
209 total_shape = first_shape + second_shape;
210 {
211 lmmc_status_t status;
212 if (f_beta_density(x, df1, df2, first_shape, second_shape, out, &status)) {
213 return status;
214 }
215 }
216
217 num = first_shape * log(df1 / df2) +
218 (first_shape - 1.0) * log(x);
219 den = total_shape * log1p(df1 * x / df2);
220 {
221 double log_beta;
222 const lmmc_status_t status =
223 lmmc_log_beta(first_shape, second_shape, &log_beta);
224 if (status != LMMC_STATUS_OK) { return status; }
225 return store_density_from_log(num - den - log_beta, out);
226 }
227}
228
230 lmmc_real_t* out) {
231 lmmc_real_t scale, result;
232 lmmc_status_t status;
233 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
234 if (!isfinite(x) || !valid_positive(df1) || !valid_positive(df2)) { return LMMC_STATUS_INVALID_ARGUMENT; }
235 if (x <= 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
236
237 if (df1 / 2.0 == 0.0) {
238 /* Beta(df1/2, df2/2) concentrates df2/(df1+df2) at zero. */
239 *out = df2 / (df1 + df2);
240 return LMMC_STATUS_OK;
241 }
242
243 scale = df2 / df1;
244 if (x > scale) {
245 lmmc_real_t ratio = scale / x;
246 lmmc_real_t tail_x = ratio / (1.0 + ratio);
247 status = regularized_beta_upper(
248 tail_x, df2 / 2.0, df1 / 2.0, &result);
249 if (status != LMMC_STATUS_OK) { return status; }
250 } else {
251 lmmc_real_t ratio = (df1 / df2) * x;
252 lmmc_real_t beta_x = ratio / (1.0 + ratio);
253 status = regularized_beta(
254 beta_x, df1 / 2.0, df2 / 2.0, &result);
255 if (status != LMMC_STATUS_OK) { return status; }
256 }
257 return store_probability_result(result, out);
258}
259
261 lmmc_real_t scale, lmmc_real_t* out) {
262 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
263 if (!isfinite(x) || !valid_positive(shape) || !valid_positive(scale)) { return LMMC_STATUS_INVALID_ARGUMENT; }
264 if (x < 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
265 if (x == 0.0) {
266 if (shape < 1.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
267 if (shape == 1.0) { return store_density_from_log(-log(scale), out); }
268 *out = 0.0; return LMMC_STATUS_OK;
269 }
270
271 if (shape >= 16.0) {
272 const lmmc_real_t standardized = x / scale;
273 if (isfinite(standardized) && standardized > 0.0) {
274 const lmmc_real_t log_density =
275 -lmmc_deviance_part(shape, standardized) -
277 log(standardized) + 0.5 * log(shape) -
278 LMMC_LOG_SQRT_2PI - log(scale);
279 return store_density_from_log(log_density, out);
280 }
281 }
282
283 return store_density_from_log(
284 (shape - 1.0) * log(x) - x / scale -
285 shape * log(scale) - lgamma(shape),
286 out);
287}
288
290 lmmc_real_t scale, lmmc_real_t* out) {
291 lmmc_real_t standardized;
292 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
293 if (!isfinite(x) || !valid_positive(shape) || !valid_positive(scale)) { return LMMC_STATUS_INVALID_ARGUMENT; }
294 if (x <= 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
295
296 standardized = x / scale;
297 if (standardized == 0.0) {
298 const lmmc_real_t log_probability =
299 shape * (log(x) - log(scale)) - lgamma(shape + 1.0);
300 return store_probability_result(exp(log_probability), out);
301 }
302 return regularized_gamma_lower(shape, standardized, out);
303}
304
305static lmmc_status_t beta_interior_density(
306 lmmc_real_t x, lmmc_real_t alpha, lmmc_real_t beta_param, lmmc_real_t* out) {
307 double logarithm;
308 const lmmc_status_t status =
309 lmmc_beta_log_kernel(x, 1.0 - x, alpha, beta_param, &logarithm);
310 if (status != LMMC_STATUS_OK) { return status; }
311 return store_density_from_log(logarithm - log(x) - log1p(-x), out);
312}
313
315 lmmc_real_t beta_param, lmmc_real_t* out) {
316 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
317 if (!isfinite(x) || !valid_positive(alpha) || !valid_positive(beta_param)) { return LMMC_STATUS_INVALID_ARGUMENT; }
318 if (x < 0.0 || x > 1.0) { *out = 0.0; return LMMC_STATUS_OK; }
319 if (x == 0.0) {
320 if (alpha < 1.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
321 if (alpha == 1.0) { *out = beta_param; return LMMC_STATUS_OK; }
322 *out = 0.0; return LMMC_STATUS_OK;
323 }
324 if (x == 1.0) {
325 if (beta_param < 1.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
326 if (beta_param == 1.0) { *out = alpha; return LMMC_STATUS_OK; }
327 *out = 0.0; return LMMC_STATUS_OK;
328 }
329
330 return beta_interior_density(x, alpha, beta_param, out);
331}
332
334 lmmc_real_t beta_param, lmmc_real_t* out) {
335 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
336 if (!isfinite(x) || !valid_positive(alpha) || !valid_positive(beta_param)) { return LMMC_STATUS_INVALID_ARGUMENT; }
337 if (x <= 0.0) { *out = 0.0; return LMMC_STATUS_OK; }
338 if (x >= 1.0) { *out = 1.0; return LMMC_STATUS_OK; }
339
340 return regularized_beta(x, alpha, beta_param, out);
341}
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
数值标量、特殊函数和 FFT 公共接口。
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_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_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)
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
#define LMMC_SQRT_2PI
基础统计量与组合数学接口。
lmmc_status_t lmmc_dist_beta_pdf(lmmc_real_t x, lmmc_real_t alpha, lmmc_real_t beta, lmmc_real_t *out)
贝塔分布概率密度函数。
lmmc_status_t lmmc_dist_chi2_cdf(lmmc_real_t x, lmmc_real_t df, lmmc_real_t *out)
χ² 分布累积分布函数。
lmmc_status_t lmmc_dist_t_cdf(lmmc_real_t x, lmmc_real_t df, lmmc_real_t *out)
t 分布累积分布函数。
lmmc_status_t lmmc_dist_normal_cdf(lmmc_real_t x, lmmc_real_t mu, lmmc_real_t sigma, lmmc_real_t *out)
正态分布累积分布函数。
lmmc_status_t lmmc_dist_gamma_pdf(lmmc_real_t x, lmmc_real_t shape, lmmc_real_t scale, lmmc_real_t *out)
伽马分布概率密度函数。
lmmc_status_t lmmc_dist_normal_pdf(lmmc_real_t x, lmmc_real_t mu, lmmc_real_t sigma, lmmc_real_t *out)
连续分布函数的公共参数约束。
lmmc_status_t lmmc_dist_beta_cdf(lmmc_real_t x, lmmc_real_t alpha, lmmc_real_t beta, lmmc_real_t *out)
贝塔分布累积分布函数。
lmmc_status_t lmmc_dist_gamma_cdf(lmmc_real_t x, lmmc_real_t shape, lmmc_real_t scale, lmmc_real_t *out)
伽马分布累积分布函数。
lmmc_status_t lmmc_dist_f_cdf(lmmc_real_t x, lmmc_real_t df1, lmmc_real_t df2, lmmc_real_t *out)
F 分布累积分布函数。
lmmc_status_t lmmc_dist_chi2_pdf(lmmc_real_t x, lmmc_real_t df, lmmc_real_t *out)
χ² 分布概率密度函数。
lmmc_status_t lmmc_dist_t_pdf(lmmc_real_t x, lmmc_real_t df, lmmc_real_t *out)
t 分布概率密度函数。
lmmc_status_t lmmc_dist_f_pdf(lmmc_real_t x, lmmc_real_t df1, lmmc_real_t df2, lmmc_real_t *out)
F 分布概率密度函数。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_INVALID_ARGUMENT