juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

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 }