dist.c (6764B)
1 /* dist.c - distribuciones (como el menu DIST de la fx-991): normal, binomial, Poisson. */ 2 #include "dist.h" 3 #include "dmath.h" 4 5 static Dec D(const char *s) { return dec_parse(s, 0); } 6 7 /* ln(n!) para n entero >= 0: producto directo hasta 20, Stirling despues */ 8 static Dec lnfact(int64_t n) 9 { 10 if (n < 2) return DEC_ZERO; 11 if (n <= 20) { 12 Dec p = DEC_ONE; 13 for (int64_t i = 2; i <= n; i++) p = dec_mul_int(p, i); 14 return d_ln(p); 15 } 16 Dec x = dec_int(n), lx = d_ln(x); 17 /* n ln n - n + ln(2πn)/2 + 1/12n - 1/360n³ + 1/1260n⁵ - 1/1680n⁷ */ 18 Dec r = dec_sub(dec_mul(x, lx), x); 19 r = dec_add(r, dec_div_int(d_ln(dec_mul(dec_mul_int(d_pi(), 2), x)), 2)); 20 Dec x2 = dec_mul(x, x), xi = dec_div(DEC_ONE, x); 21 r = dec_add(r, dec_div_int(xi, 12)); 22 xi = dec_div(xi, x2); r = dec_sub(r, dec_div_int(xi, 360)); 23 xi = dec_div(xi, x2); r = dec_add(r, dec_div_int(xi, 1260)); 24 xi = dec_div(xi, x2); r = dec_sub(r, dec_div_int(xi, 1680)); 25 return r; 26 } 27 28 /* erfc(x) para x >= 0 */ 29 static Dec erfc_pos(Dec x) 30 { 31 if (dec_cmp(x, D("2.5")) < 0) { 32 /* 1 - erf(x), erf por serie: 2/√π Σ (-1)^n x^(2n+1) / (n! (2n+1)) */ 33 Dec x2 = dec_mul(x, x), t = x, sum = x; 34 for (int n = 1; n < 200; n++) { 35 t = dec_neg(dec_div_int(dec_mul(t, x2), n)); 36 Dec term = dec_div_int(t, 2 * n + 1); 37 sum = dec_add(sum, term); 38 if (!term.m || term.e < sum.e - 20) break; 39 } 40 Dec erf = dec_div(dec_mul_int(sum, 2), dec_sqrt(d_pi())); 41 return dec_sub(DEC_ONE, erf); 42 } 43 if (dec_cmp(x, D("27")) > 0) return DEC_ZERO; 44 /* fraccion continua (Lentz): erfc x = e^(-x²)/√π · 1/(x + (1/2)/(x + 1/(x + (3/2)/(x + ...)))) */ 45 Dec tiny = D("1e-90"), f = x, C = x, Dd = DEC_ZERO; 46 for (int k = 1; k < 400; k++) { 47 Dec a = dec_div_int(dec_int(k), 2); 48 Dd = dec_add(x, dec_mul(a, Dd)); 49 if (!Dd.m) Dd = tiny; 50 C = dec_add(x, dec_div(a, C)); 51 if (!C.m) C = tiny; 52 Dd = dec_div(DEC_ONE, Dd); 53 Dec delta = dec_mul(C, Dd); 54 f = dec_mul(f, delta); 55 Dec d1 = dec_abs(dec_sub(delta, DEC_ONE)); 56 if (!d1.m || d1.e < -18) break; 57 } 58 return dec_div(d_exp(dec_neg(dec_mul(x, x))), dec_mul(f, dec_sqrt(d_pi()))); 59 } 60 61 /* Φ(z) y su complemento, cada uno preciso en su cola */ 62 static Dec phi(Dec z) 63 { 64 Dec r2 = dec_sqrt(dec_int(2)); 65 Dec e = erfc_pos(dec_div(dec_abs(z), r2)); 66 return z.neg ? dec_div_int(e, 2) : dec_sub(DEC_ONE, dec_div_int(e, 2)); 67 } 68 69 static Dec npdf(Dec z) /* densidad normal estandar */ 70 { 71 return dec_div(d_exp(dec_neg(dec_div_int(dec_mul(z, z), 2))), dec_sqrt(dec_mul_int(d_pi(), 2))); 72 } 73 74 static bool sigma_ok(Dec s) { return !s.err && s.m && !s.neg; } 75 76 Dec dist_npd(Dec x, Dec s, Dec mu) 77 { 78 if (!sigma_ok(s)) return dec_err(); 79 return dec_div(npdf(dec_div(dec_sub(x, mu), s)), s); 80 } 81 82 Dec dist_ncd(Dec lo, Dec hi, Dec s, Dec mu) 83 { 84 if (!sigma_ok(s)) return dec_err(); 85 Dec a = dec_div(dec_sub(lo, mu), s), b = dec_div(dec_sub(hi, mu), s); 86 if (dec_cmp(a, b) > 0) { Dec t = a; a = b; b = t; } 87 /* en la cola derecha conviene restar complementos */ 88 Dec r; 89 if (!a.neg && a.m) { 90 Dec r2 = dec_sqrt(dec_int(2)); 91 r = dec_div_int(dec_sub(erfc_pos(dec_div(a, r2)), erfc_pos(dec_div(b, r2))), 2); 92 } else r = dec_sub(phi(b), phi(a)); 93 return dec_round_sig(r, 15); 94 } 95 96 Dec dist_invn(Dec p, Dec s, Dec mu) 97 { 98 if (!sigma_ok(s) || p.err || p.neg || !p.m || dec_cmp(p, DEC_ONE) >= 0) return dec_err(); 99 /* primera aproximacion (Abramowitz-Stegun 26.2.23) y despues Newton sobre Φ */ 100 bool low = dec_cmp(p, D("0.5")) < 0; 101 Dec q = low ? p : dec_sub(DEC_ONE, p); 102 Dec t = dec_sqrt(dec_mul_int(d_ln(q), -2)); 103 Dec num = dec_add(D("2.515517"), dec_add(dec_mul(D("0.802853"), t), dec_mul(D("0.010328"), dec_mul(t, t)))); 104 Dec den = dec_add(DEC_ONE, dec_add(dec_mul(D("1.432788"), t), 105 dec_add(dec_mul(D("0.189269"), dec_mul(t, t)), dec_mul(D("0.001308"), dec_mul(dec_mul(t, t), t))))); 106 Dec z = dec_sub(t, dec_div(num, den)); 107 if (low) z = dec_neg(z); 108 for (int i = 0; i < 12; i++) { 109 Dec f = dec_sub(phi(z), p), d = npdf(z); 110 if (!d.m) break; 111 Dec step = dec_div(f, d); 112 z = dec_sub(z, step); 113 if (!step.m || step.e < -17) break; 114 } 115 return dec_round_sig(dec_add(mu, dec_mul(s, z)), 15); 116 } 117 118 /* P(X = k) con log para no desbordar */ 119 static Dec binom_term(int64_t k, int64_t n, Dec lp, Dec lq) 120 { 121 Dec l = dec_sub(dec_sub(lnfact(n), lnfact(k)), lnfact(n - k)); 122 l = dec_add(l, dec_add(dec_mul_int(lp, k), dec_mul_int(lq, n - k))); 123 return d_exp(l); 124 } 125 126 static bool binom_args(Dec x, Dec n, Dec p, int64_t *k, int64_t *N) 127 { 128 return !p.err && !p.neg && dec_cmp(p, DEC_ONE) <= 0 && dec_to_int(n, N) && *N >= 0 && *N <= 100000 && 129 dec_to_int(x, k); 130 } 131 132 /* casos borde p = 0 y p = 1 */ 133 static bool binom_edge(int64_t k, int64_t N, Dec p, bool cum, Dec *out) 134 { 135 if (p.m && dec_cmp(p, DEC_ONE) != 0) return false; 136 int64_t at = p.m ? N : 0; /* todo el peso en 0 o en N */ 137 *out = (cum ? k >= at : k == at) ? DEC_ONE : DEC_ZERO; 138 return true; 139 } 140 141 Dec dist_bpd(Dec x, Dec n, Dec p) 142 { 143 int64_t k, N; 144 if (!binom_args(x, n, p, &k, &N)) return dec_err(); 145 if (k < 0 || k > N) return DEC_ZERO; 146 Dec r; 147 if (binom_edge(k, N, p, false, &r)) return r; 148 return dec_round_sig(binom_term(k, N, d_ln(p), d_ln(dec_sub(DEC_ONE, p))), 15); 149 } 150 151 Dec dist_bcd(Dec x, Dec n, Dec p) 152 { 153 int64_t k, N; 154 if (!binom_args(x, n, p, &k, &N)) return dec_err(); 155 if (k < 0) return DEC_ZERO; 156 if (k >= N) return DEC_ONE; 157 Dec r; 158 if (binom_edge(k, N, p, true, &r)) return r; 159 if (k > 20000) return dec_err(); 160 Dec lp = d_ln(p), lq = d_ln(dec_sub(DEC_ONE, p)), s = DEC_ZERO; 161 for (int64_t i = 0; i <= k; i++) s = dec_add(s, binom_term(i, N, lp, lq)); 162 if (dec_cmp(s, DEC_ONE) > 0) s = DEC_ONE; 163 return dec_round_sig(s, 15); 164 } 165 166 static Dec pois_term(int64_t k, Dec lam, Dec ll) 167 { 168 return d_exp(dec_sub(dec_sub(dec_mul_int(ll, k), lam), lnfact(k))); 169 } 170 171 Dec dist_ppd(Dec x, Dec lam) 172 { 173 int64_t k; 174 if (lam.err || lam.neg || !lam.m || !dec_to_int(x, &k)) return dec_err(); 175 if (k < 0) return DEC_ZERO; 176 return dec_round_sig(pois_term(k, lam, d_ln(lam)), 15); 177 } 178 179 Dec dist_pcd(Dec x, Dec lam) 180 { 181 int64_t k; 182 if (lam.err || lam.neg || !lam.m || !dec_to_int(x, &k)) return dec_err(); 183 if (k < 0) return DEC_ZERO; 184 if (k > 20000) return dec_err(); 185 Dec ll = d_ln(lam), s = DEC_ZERO; 186 for (int64_t i = 0; i <= k; i++) s = dec_add(s, pois_term(i, lam, ll)); 187 if (dec_cmp(s, DEC_ONE) > 0) s = DEC_ONE; 188 return dec_round_sig(s, 15); 189 }