LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
probability_quantiles.c
浏览该文件的文档.
2
4static lmmc_real_t normal_quantile_rational(lmmc_real_t p) {
5 static const double a[] = {
6 -3.969683028665376e+01, 2.209460984245205e+02,
7 -2.759285104469687e+02, 1.383577518672690e+02,
8 -3.066479806614716e+01, 2.506628277459239e+00
9 };
10 static const double b[] = {
11 -5.447609879822406e+01, 1.615858368580409e+02,
12 -1.556989798598866e+02, 6.680131188771972e+01,
13 -1.328068155288572e+01
14 };
15 static const double c[] = {
16 -7.784894002430293e-03, -3.223964580411365e-01,
17 -2.400758277161838e+00, -2.549732539343734e+00,
18 4.374664141464968e+00, 2.938163982698783e+00
19 };
20 static const double d[] = {
21 7.784695709041462e-03, 3.224671290700398e-01,
22 2.445134137142996e+00, 3.754408661907416e+00
23 };
24
25 double q, r;
26 double plow = 0.02425;
27 double phigh = 1.0 - plow;
28
29 if (p < plow) {
31 q = sqrt(-2.0 * log(p));
32 return (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
33 ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1.0);
34 } else if (p <= phigh) {
36 q = p - 0.5;
37 r = q * q;
38 return (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q /
39 (((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1.0);
40 } else {
42 q = sqrt(-2.0 * log(1.0 - p));
43 return -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
44 ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1.0);
45 }
46}
47
49 lmmc_real_t, const void*, lmmc_real_t*);
50
55
56static lmmc_status_t eval_t_cdf(
57 lmmc_real_t x, const void* context, lmmc_real_t* out) {
58 const distribution_parameters_t* parameters =
59 (const distribution_parameters_t*)context;
60 return lmmc_dist_t_cdf(x, parameters->first, out);
61}
62
63static lmmc_status_t eval_t_pdf(
64 lmmc_real_t x, const void* context, lmmc_real_t* out) {
65 const distribution_parameters_t* parameters =
66 (const distribution_parameters_t*)context;
67 return lmmc_dist_t_pdf(x, parameters->first, out);
68}
69
70static lmmc_status_t eval_chi2_cdf(
71 lmmc_real_t x, const void* context, lmmc_real_t* out) {
72 const distribution_parameters_t* parameters =
73 (const distribution_parameters_t*)context;
74 return lmmc_dist_chi2_cdf(x, parameters->first, out);
75}
76
77static lmmc_status_t eval_chi2_pdf(
78 lmmc_real_t x, const void* context, lmmc_real_t* out) {
79 const distribution_parameters_t* parameters =
80 (const distribution_parameters_t*)context;
81 return lmmc_dist_chi2_pdf(x, parameters->first, out);
82}
83
84static lmmc_status_t eval_f_cdf(
85 lmmc_real_t x, const void* context, lmmc_real_t* out) {
86 const distribution_parameters_t* parameters =
87 (const distribution_parameters_t*)context;
88 return lmmc_dist_f_cdf(
89 x, parameters->first, parameters->second, out);
90}
91
92static lmmc_status_t eval_f_pdf(
93 lmmc_real_t x, const void* context, lmmc_real_t* out) {
94 const distribution_parameters_t* parameters =
95 (const distribution_parameters_t*)context;
96 return lmmc_dist_f_pdf(
97 x, parameters->first, parameters->second, out);
98}
99
100static lmmc_status_t eval_gamma_cdf(
101 lmmc_real_t x, const void* context, lmmc_real_t* out) {
102 const distribution_parameters_t* parameters =
103 (const distribution_parameters_t*)context;
104 return lmmc_dist_gamma_cdf(
105 x, parameters->first, parameters->second, out);
106}
107
108static lmmc_status_t eval_gamma_pdf(
109 lmmc_real_t x, const void* context, lmmc_real_t* out) {
110 const distribution_parameters_t* parameters =
111 (const distribution_parameters_t*)context;
112 return lmmc_dist_gamma_pdf(
113 x, parameters->first, parameters->second, out);
114}
115
116static lmmc_status_t eval_beta_cdf(
117 lmmc_real_t x, const void* context, lmmc_real_t* out) {
118 const distribution_parameters_t* parameters =
119 (const distribution_parameters_t*)context;
120 return lmmc_dist_beta_cdf(
121 x, parameters->first, parameters->second, out);
122}
123
124static lmmc_status_t eval_beta_pdf(
125 lmmc_real_t x, const void* context, lmmc_real_t* out) {
126 const distribution_parameters_t* parameters =
127 (const distribution_parameters_t*)context;
128 return lmmc_dist_beta_pdf(
129 x, parameters->first, parameters->second, out);
130}
131
132static lmmc_status_t evaluate_distribution(
133 distribution_eval_fn function,
134 lmmc_real_t x,
135 const void* context,
136 lmmc_real_t* value) {
137 lmmc_status_t status = function(x, context, value);
138 if (status != LMMC_STATUS_OK) { return status; }
139 if (!isfinite(*value)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
140 return LMMC_STATUS_OK;
141}
142
143static int quantile_probability_close(lmmc_real_t value, lmmc_real_t target) {
144 const lmmc_real_t tail = fmin(target, 1.0 - target);
145 return fabs(value - target) <= 1e-12 * tail;
146}
147
148static lmmc_status_t finish_quantile_bracket(
149 lmmc_real_t probability,
150 lmmc_real_t lower,
151 lmmc_real_t lower_cdf,
152 lmmc_real_t upper,
153 lmmc_real_t upper_cdf,
154 lmmc_real_t* out) {
155 if (quantile_probability_close(lower_cdf, probability)) {
156 *out = lower;
157 return LMMC_STATUS_OK;
158 }
159 if (quantile_probability_close(upper_cdf, probability)) {
160 *out = upper;
161 return LMMC_STATUS_OK;
162 }
164}
165
166static lmmc_status_t expand_quantile_lower(
167 lmmc_real_t probability, lmmc_real_t* bound, lmmc_real_t* value,
168 distribution_eval_fn cdf, const void* context) {
169 int iteration;
170 lmmc_status_t status;
171 for (iteration = 0; *value > probability;
172 ++iteration) {
173 if (iteration >= 1024 || *bound <= -DBL_MAX) {
175 }
176 *bound = *bound <= -DBL_MAX / 2.0 ? -DBL_MAX : *bound * 2.0;
177 status = evaluate_distribution(cdf, *bound, context, value);
178 if (status != LMMC_STATUS_OK) { return status; }
179 }
180 return LMMC_STATUS_OK;
181}
182
183static lmmc_status_t expand_quantile_upper(
184 lmmc_real_t probability, lmmc_real_t* bound, lmmc_real_t* value,
185 distribution_eval_fn cdf, const void* context) {
186 int iteration;
187 lmmc_status_t status;
188 for (iteration = 0; *value < probability;
189 ++iteration) {
190 if (iteration >= 1024 || *bound >= DBL_MAX) {
192 }
193 *bound = *bound >= DBL_MAX / 2.0 ? DBL_MAX : *bound * 2.0;
194 status = evaluate_distribution(cdf, *bound, context, value);
195 if (status != LMMC_STATUS_OK) { return status; }
196 }
197 return LMMC_STATUS_OK;
198}
199
200static lmmc_real_t quantile_newton_candidate(
201 lmmc_real_t probability, lmmc_real_t x, lmmc_real_t cdf_value,
203 const void* context) {
204 lmmc_real_t pdf_value;
205 lmmc_status_t status = pdf(x, context, &pdf_value);
206 lmmc_real_t candidate = NAN;
207 if (status == LMMC_STATUS_OK && isfinite(pdf_value) && pdf_value > DBL_MIN) {
208 candidate = x - (cdf_value - probability) / pdf_value;
209 }
210 if (!isfinite(candidate) || candidate <= lower || candidate >= upper) {
211 candidate = lower * 0.5 + upper * 0.5;
212 }
213 return candidate;
214}
215
216static lmmc_status_t refine_quantile_bracket(
217 lmmc_real_t probability, lmmc_real_t initial, lmmc_real_t lower, lmmc_real_t upper,
218 lmmc_real_t lower_cdf, lmmc_real_t upper_cdf, distribution_eval_fn cdf,
219 distribution_eval_fn pdf, const void* context, lmmc_real_t* out) {
220 int iteration;
221 lmmc_real_t x;
222 lmmc_status_t status;
223 x = initial;
224 if (!isfinite(x) || x <= lower || x >= upper) {
225 x = lower * 0.5 + upper * 0.5;
226 }
227 for (iteration = 0; iteration < 2048; ++iteration) {
228 lmmc_real_t cdf_value, candidate;
229 status = evaluate_distribution(cdf, x, context, &cdf_value);
230 if (status != LMMC_STATUS_OK) { return status; }
231 if (quantile_probability_close(cdf_value, probability)) {
232 *out = x;
233 return LMMC_STATUS_OK;
234 }
235
236 if (cdf_value < probability) {
237 lower = x;
238 lower_cdf = cdf_value;
239 } else {
240 upper = x;
241 upper_cdf = cdf_value;
242 }
243 if (nextafter(lower, upper) == upper) {
244 return finish_quantile_bracket(
245 probability, lower, lower_cdf, upper, upper_cdf, out);
246 }
247
248 candidate = quantile_newton_candidate(
249 probability, x, cdf_value, lower, upper, pdf, context);
250 if (candidate == lower || candidate == upper) {
251 return finish_quantile_bracket(
252 probability, lower, lower_cdf, upper, upper_cdf, out);
253 }
254 x = candidate;
255 }
257}
258
259static lmmc_status_t bracketed_quantile(
260 lmmc_real_t probability,
261 lmmc_real_t initial,
262 lmmc_real_t lower,
263 lmmc_real_t upper,
264 int expand_lower,
265 int expand_upper,
268 const void* context,
269 lmmc_real_t* out) {
270 lmmc_real_t lower_cdf, upper_cdf;
271 lmmc_status_t status;
272
273 status = evaluate_distribution(cdf, lower, context, &lower_cdf);
274 if (status != LMMC_STATUS_OK) { return status; }
275 status = evaluate_distribution(cdf, upper, context, &upper_cdf);
276 if (status != LMMC_STATUS_OK) { return status; }
277
278 if (expand_lower) {
279 status = expand_quantile_lower(probability, &lower, &lower_cdf, cdf, context);
280 if (status != LMMC_STATUS_OK) {
281 return status;
282 }
283 }
284 if (expand_upper) {
285 status = expand_quantile_upper(probability, &upper, &upper_cdf, cdf, context);
286 if (status != LMMC_STATUS_OK) {
287 return status;
288 }
289 }
290 if (lower_cdf > probability || upper_cdf < probability) {
292 }
293 return refine_quantile_bracket(probability, initial, lower, upper,
294 lower_cdf, upper_cdf, cdf, pdf, context, out);
295}
296
297
299 lmmc_real_t sigma, lmmc_real_t* out) {
300 lmmc_real_t result;
301 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
302 if (!isfinite(mu) || !valid_positive(sigma) || !valid_probability(p)) { return LMMC_STATUS_INVALID_ARGUMENT; }
303
304 result = fma(sigma, normal_quantile_rational(p), mu);
305 if (!isfinite(result)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
306 *out = result;
307 return LMMC_STATUS_OK;
308}
309
311 distribution_parameters_t parameters;
312 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
313 if (!valid_positive(df) || !valid_probability(p)) { return LMMC_STATUS_INVALID_ARGUMENT; }
314 if (student_t_uses_normal_limit(df)) {
315 const lmmc_real_t result = normal_quantile_rational(p);
316 if (!isfinite(result)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
317 *out = result;
318 return LMMC_STATUS_OK;
319 }
320
321 parameters.first = df;
322 parameters.second = 0.0;
323 return bracketed_quantile(
324 p, normal_quantile_rational(p), -1.0, 1.0, 1, 1,
325 eval_t_cdf, eval_t_pdf, &parameters, out);
326}
327
329 distribution_parameters_t parameters;
330 lmmc_real_t z, term, initial;
331 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
332 if (!valid_positive(df) || !valid_probability(p)) { return LMMC_STATUS_INVALID_ARGUMENT; }
333
334 z = normal_quantile_rational(p);
335 term = 1.0 - 2.0 / (9.0 * df) + z * sqrt(2.0 / (9.0 * df));
336 initial = df * term * term * term;
337 if (!isfinite(initial) || initial <= 0.0) {
338 initial = 1.0;
339 }
340 parameters.first = df;
341 parameters.second = 0.0;
342 return bracketed_quantile(
343 p, initial, 0.0, fmax(initial, 1.0), 0, 1,
344 eval_chi2_cdf, eval_chi2_pdf, &parameters, out);
345}
346
348 lmmc_real_t* out) {
349 distribution_parameters_t parameters;
350 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
351 if (!valid_positive(df1) || !valid_positive(df2) || !valid_probability(p)) { return LMMC_STATUS_INVALID_ARGUMENT; }
352
353 parameters.first = df1;
354 parameters.second = df2;
355 return bracketed_quantile(
356 p, 1.0, 0.0, 1.0, 0, 1,
357 eval_f_cdf, eval_f_pdf, &parameters, out);
358}
359
361 lmmc_real_t scale, lmmc_real_t* out) {
362 distribution_parameters_t parameters;
363 lmmc_real_t initial;
364 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
365 if (!valid_positive(shape) || !valid_positive(scale) || !valid_probability(p)) { return LMMC_STATUS_INVALID_ARGUMENT; }
366
367 initial = shape * scale;
368 if (!isfinite(initial) || initial <= 0.0) {
369 initial = 1.0;
370 }
371 parameters.first = shape;
372 parameters.second = scale;
373 return bracketed_quantile(
374 p, initial, 0.0, fmax(initial, 1.0), 0, 1,
375 eval_gamma_cdf, eval_gamma_pdf, &parameters, out);
376}
377
379 lmmc_real_t beta_param, lmmc_real_t* out) {
380 distribution_parameters_t parameters;
381 lmmc_real_t ratio, initial;
382 if (!out) { return LMMC_STATUS_INVALID_ARGUMENT; }
383 if (!valid_positive(alpha) || !valid_positive(beta_param) ||
384 !valid_probability(p)) { return LMMC_STATUS_INVALID_ARGUMENT; }
385
386 if (alpha >= beta_param) {
387 initial = 1.0 / (1.0 + beta_param / alpha);
388 } else {
389 ratio = alpha / beta_param;
390 initial = ratio / (1.0 + ratio);
391 }
392 parameters.first = alpha;
393 parameters.second = beta_param;
394 return bracketed_quantile(
395 p, initial, 0.0, 1.0, 0, 0,
396 eval_beta_cdf, eval_beta_pdf, &parameters, out);
397}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_status_t(*) distribution_eval_fn(lmmc_real_t, const void *, lmmc_real_t *)
lmmc_status_t lmmc_dist_chi2_quantile(lmmc_real_t p, lmmc_real_t df, lmmc_real_t *out)
χ² 分布分位数函数。
lmmc_status_t lmmc_dist_normal_quantile(lmmc_real_t p, lmmc_real_t mu, lmmc_real_t sigma, lmmc_real_t *out)
正态分布分位数函数(逆 CDF)。
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_gamma_quantile(lmmc_real_t p, lmmc_real_t shape, lmmc_real_t scale, lmmc_real_t *out)
伽马分布分位数函数。
lmmc_status_t lmmc_dist_f_quantile(lmmc_real_t p, lmmc_real_t df1, lmmc_real_t df2, lmmc_real_t *out)
F 分布分位数函数。
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_t_quantile(lmmc_real_t p, lmmc_real_t df, lmmc_real_t *out)
t 分布分位数函数。
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_beta_quantile(lmmc_real_t p, lmmc_real_t alpha, lmmc_real_t beta, 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_CONVERGENCE_FAILED
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_INVALID_ARGUMENT
@ LMMC_STATUS_OUT_OF_RANGE