selftest_calc.c (16819B)
1 /* selftest_calc.c - expresiones de punta a punta: texto -> tokens -> RPN -> Num -> formato. */ 2 #include <stdio.h> 3 #include <string.h> 4 #include "selftest.h" 5 #include "eval.h" 6 #include "fmt.h" 7 #include "dmath.h" 8 #include "str.h" 9 10 typedef struct { const char *in; int ang; const char *exact, *dec; } Case; 11 12 /* exact: lo que muestra en modo exacto; dec: con S⇔D (o "" si es igual) */ 13 static const Case CASES[] = { 14 { "1+2", ANG_DEG, "3", "" }, 15 { "0.1+0.2", ANG_DEG, "3/10", "0.3" }, 16 { "\\f{1}{3}+\\f{1}{6}", ANG_DEG, "1/2", "0.5" }, 17 { "1:3", ANG_DEG, "1/3", "0.3333333333" }, 18 { "2:3*3", ANG_DEG, "2", "" }, 19 { "-2^{2}", ANG_DEG, "-4", "" }, 20 { "(-2)^{2}", ANG_DEG, "4", "" }, 21 { "2^{3}^{2}", ANG_DEG, "64", "" }, 22 { "1:2\\pi", ANG_DEG, "0.1591549431", "" }, 23 { "\\r{8}", ANG_DEG, "2√2", "2.828427125" }, 24 { "\\r{12}+\\r{3}", ANG_DEG, "3√3", "5.196152423" }, 25 { "\\f{1}{\\r{2}}", ANG_DEG, "√2/2", "0.7071067812" }, 26 { "\\f{1+\\r{5}}{2}", ANG_DEG, "(1+√5)/2", "1.618033989" }, 27 { "\\r{2}*\\r{3}", ANG_DEG, "√6", "2.449489743" }, 28 { "\\r{-4}", ANG_DEG, "Error", "" }, 29 { "sin(30)", ANG_DEG, "1/2", "0.5" }, 30 { "sin(30", ANG_DEG, "1/2", "0.5" }, 31 { "cos(45)", ANG_DEG, "√2/2", "0.7071067812" }, 32 { "tan(60)", ANG_DEG, "√3", "1.732050808" }, 33 { "tan(90)", ANG_DEG, "Error", "" }, 34 { "sin(18)", ANG_DEG, "(-1+√5)/4", "0.3090169944" }, 35 { "sin(\\f{\\pi}{6})", ANG_RAD, "1/2", "0.5" }, 36 { "cos(\\pi)", ANG_RAD, "-1", "" }, 37 { "sin(1)", ANG_RAD, "0.8414709848", "" }, 38 { "asin(\\f{1}{2})", ANG_DEG, "30", "" }, 39 { "asin(\\f{1}{2})", ANG_RAD, "π/6", "0.5235987756" }, 40 { "acos(-1)", ANG_RAD, "π", "3.141592654" }, 41 { "atan(1)", ANG_GRA, "50", "" }, 42 { "2\\pi", ANG_DEG, "2π", "6.283185307" }, 43 { "\\pi:4*3", ANG_DEG, "3π/4", "2.35619449" }, 44 { "log(1000)", ANG_DEG, "3", "" }, 45 { "\\l{2}{8}", ANG_DEG, "3", "" }, 46 { "\\l{2}{\\f{1}{8}}", ANG_DEG, "-3", "" }, 47 { "ln(1)", ANG_DEG, "0", "" }, 48 { "ln(0)", ANG_DEG, "Error", "" }, 49 { "e^{1}", ANG_DEG, "2.718281828", "" }, 50 { "5!", ANG_DEG, "120", "" }, 51 { "10\\C3", ANG_DEG, "120", "" }, 52 { "10\\P3", ANG_DEG, "720", "" }, 53 { "50%", ANG_DEG, "1/2", "0.5" }, 54 { "2\\inv", ANG_DEG, "1/2", "0.5" }, 55 { "\\n{3}{-27}", ANG_DEG, "-3", "" }, 56 { "\\n{3}{2}", ANG_DEG, "1.25992105", "" }, 57 { "8^{\\f{1}{3}}", ANG_DEG, "2", "" }, 58 { "4^{1.5}", ANG_DEG, "8", "" }, 59 { "2^{0.5}", ANG_DEG, "√2", "1.414213562" }, 60 { "\\a{-3}", ANG_DEG, "3", "" }, 61 { "\\m{1}{1}{2}", ANG_DEG, "3/2", "1.5" }, 62 { "1.5\\E3", ANG_DEG, "1500", "" }, 63 { "1\\E-3", ANG_DEG, "1/1000", "1E-3" }, 64 { "123456789*987654321", ANG_DEG, "1.219326311E17", "" }, 65 { "2^{100}", ANG_DEG, "1.2676506E30", "" }, 66 { "1:7^{20}", ANG_DEG, "1.253254289E-17", "" }, 67 { "gcd(12,18)", ANG_DEG, "6", "" }, 68 { "lcm(4,6)", ANG_DEG, "12", "" }, 69 { "int(-2.5)", ANG_DEG, "-2", "" }, 70 { "intg(-2.5)", ANG_DEG, "-3", "" }, 71 { "2(3+4)", ANG_DEG, "14", "" }, 72 { "(1+2)(3+4)", ANG_DEG, "21", "" }, 73 { "2sin(30)", ANG_DEG, "1", "" }, 74 { "1+", ANG_DEG, "Syntax", "" }, 75 { "\\f{}{2}", ANG_DEG, "Syntax", "" }, 76 { "(1+2", ANG_DEG, "3", "" }, 77 { "1:0", ANG_DEG, "Error", "" }, 78 { "sinh(1)", ANG_DEG, "1.175201194", "" }, 79 { "\\vA+1", ANG_DEG, "1", "" }, 80 { "e", ANG_DEG, "2.718281828", "" }, 81 { "3\\pi-\\pi", ANG_DEG, "2π", "6.283185307" }, 82 { "\\f{2}{4}", ANG_DEG, "1/2", "0.5" }, 83 { "\\f{\\r{3}}{2}*\\f{\\r{3}}{2}", ANG_DEG, "3/4", "0.75" }, 84 { "\\f{1}{1+\\r{2}}", ANG_DEG, "-1+√2", "0.4142135624" }, 85 /* analisis */ 86 { "\\i{0}{1}{x^{2}}", ANG_DEG, "0.3333333333", "" }, 87 { "\\i{0}{\\pi}{sin(x)}", ANG_RAD, "2", "" }, 88 { "\\i{0}{1}{\\f{4}{1+x^{2}}}", ANG_DEG, "3.141592654", "" }, 89 { "\\i{1}{\\e}{\\f{1}{x}}", ANG_DEG, "1", "" }, 90 { "\\i{0}{2}{\\i{0}{1}{x}}", ANG_DEG, "1", "" }, 91 { "\\i{0}{10}{\\e^{-x}}", ANG_DEG, "0.9999546001", "" }, 92 { "\\d{x^{3}}{2}", ANG_DEG, "12", "" }, 93 { "\\d{sin(x)}{0}", ANG_RAD, "1", "" }, 94 { "\\d{ln(x)}{4}", ANG_DEG, "0.25", "" }, 95 { "\\s{1}{100}{x}", ANG_DEG, "5050", "" }, 96 { "\\s{1}{4}{\\f{1}{x}}", ANG_DEG, "25/12", "2.083333333" }, 97 { "\\p{1}{5}{x}", ANG_DEG, "120", "" }, 98 { "\\s{1}{10}{x}+\\vX", ANG_DEG, "55", "" }, 99 /* distribuciones (valores de referencia de tablas) */ 100 { "normpd(0,1,0)", ANG_DEG, "0.3989422804", "" }, 101 { "normcd(-1,1,1,0)", ANG_DEG, "0.6826894921", "" }, 102 { "normcd(6,1\\E99,1,0)", ANG_DEG, "9.86587645E-10", "" }, 103 { "invnorm(0.975,1,0)", ANG_DEG, "1.959963985", "" }, 104 { "invnorm(0.05,2,10)", ANG_DEG, "6.710292746", "" }, 105 { "binompd(3,10,0.5)", ANG_DEG, "0.1171875", "" }, 106 { "binomcd(3,10,0.5)", ANG_DEG, "0.171875", "" }, 107 { "binompd(500,1000,0.5)", ANG_DEG, "0.02522501818", "" }, 108 { "poisspd(2,3)", ANG_DEG, "0.2240418077", "" }, 109 { "poisscd(2,3)", ANG_DEG, "0.4231900811", "" }, 110 /* sexagesimal */ 111 { "12\\deg30\\deg", ANG_DEG, "25/2", "12.5" }, 112 { "1\\deg30\\deg36\\deg", ANG_DEG, "151/100", "1.51" }, 113 { "sin(30\\deg)", ANG_DEG, "1/2", "0.5" }, 114 }; 115 116 static int run(const char *in, int ang, bool want_dec, char *out, int n) 117 { 118 static Expr e; 119 static Num vars[NVARS]; 120 if (!expr_from_text(&e, in)) return snprintf(out, n, "Texto?"); 121 EvalCtx cx = { 0 }; 122 cx.ang = ang; 123 cx.vars = vars; 124 cx.ans = num_int(0); 125 cx.preans = num_int(0); 126 Num r; 127 int pos, err = calc_eval(&e, &cx, &r, &pos); 128 if (err == CE_SYNTAX) return snprintf(out, n, "Syntax"); 129 if (err) return snprintf(out, n, "Error"); 130 Fmt f; 131 fmt_default(&f); 132 return fmt_plain(&r, &f, want_dec, out, n); 133 } 134 135 void selftest_calc(void) 136 { 137 char got[128]; 138 for (size_t i = 0; i < sizeof CASES / sizeof CASES[0]; i++) { 139 const Case *c = &CASES[i]; 140 run(c->in, c->ang, false, got, sizeof got); 141 st_check(!strcmp(got, c->exact), "%-28s = %s (esperaba %s)", c->in, got, c->exact); 142 if (c->dec[0]) { 143 run(c->in, c->ang, true, got, sizeof got); 144 st_check(!strcmp(got, c->dec), "%-28s ≈ %s (esperaba %s)", c->in, got, c->dec); 145 } 146 } 147 } 148 149 /* ./calc --eval "texto": muestra exacto y decimal */ 150 int eval_cli(const char *in) 151 { 152 char a[128], b[128]; 153 run(in, ANG_DEG, false, a, sizeof a); 154 run(in, ANG_DEG, true, b, sizeof b); 155 printf("%s\n", a); 156 if (strcmp(a, b)) printf("%s\n", b); 157 return 0; 158 } 159 160 /* edicion: se tipea la secuencia (con '<' = BKSP, '[' = izquierda, ']' = derecha) */ 161 static void typed(const char *keys, const char *want, int want_cur) 162 { 163 static Expr e; 164 char got[256]; 165 ex_clear(&e); 166 for (const char *k = keys; *k; k++) { 167 if (*k == '<') ex_backspace(&e); 168 else if (*k == '[') ex_left(&e); 169 else if (*k == ']') ex_right(&e); 170 else if (*k == '*') ex_insert(&e, T_MUL); 171 else ex_insert(&e, (unsigned char)*k); 172 } 173 expr_to_text(&e, got, sizeof got); 174 st_check(!strcmp(got, want) && (want_cur < 0 || e.cur == want_cur), "tipear %-14s -> %s cur %d (esperaba %s cur %d)", 175 keys, got, e.cur, want, want_cur); 176 } 177 178 void selftest_edit(void) 179 { 180 typed("1/2+1", "\\F{1}{2}+1", -1); 181 typed("/", "\\f{}{}", 1); 182 typed("/3]4", "\\f{3}{4}", 4); 183 typed("12/34", "\\F{12}{34}", 6); 184 typed("sqrt(2)+1", "\\r{2}+1", -1); 185 typed("sqrt(2+3)", "\\r{2+3}", -1); 186 typed("2^3+1", "2^{3}+1", -1); 187 typed("2^-3", "2^{-3}", -1); 188 typed("pi", "\\pi", -1); 189 typed("2pi", "2\\pi", -1); 190 typed("ans+1", "\\ans+1", -1); 191 typed("sin(30", "sin(30", -1); 192 typed("asin(1", "asin(1", -1); 193 typed("1/(2+3)+1", "\\F{1}{2+3}+1", -1); 194 typed("(1+2)/3", "\\F{1+2}{3}", -1); 195 typed("2^(1+2)*3", "2^{1+2}*3", -1); 196 typed("(1)(2)/3", "(1)\\F{2}{3}", -1); 197 typed("sin(30)/2", "\\F{sin(30)}{2}", -1); 198 typed("2^3/4", "\\F{2^{3}}{4}", -1); 199 typed("1/2<<", "\\F{1}{}", 2); 200 typed("1/2<<<<", "", 0); 201 typed("abs(-3)", "\\a{-3}", -1); 202 typed("cbrt(8)", "\\n{3}{8}", -1); 203 typed("exp(2)", "\\e\\x{2}", -1); 204 typed("Ax2", "\\vAx2", -1); 205 typed("1/2*3", "\\F{1}{2}*3", -1); 206 typed("12[[/", "\\f{}{}12", 1); 207 typed("integ(0,1,x^2)", "\\i{0}{1}{x^{2}}", -1); 208 typed("deriv(x^3,2)", "\\d{x^{3}}{2}", -1); 209 typed("sum(1,10,x)+1", "\\s{1}{10}{x}+1", -1); 210 typed("logb(2,8)", "\\l{2}{8}", -1); 211 } 212 213 #include "calc.h" 214 215 static void keys(Calc *c, const char *k) 216 { 217 for (; *k; k++) { 218 int key = (unsigned char)*k; 219 if (key == '~') key = K_OK; 220 else if (key == '<') key = K_BACK; 221 else if (key == '\t') key = K_TAB; 222 else if (key == 'v') key = K_DOWN; /* (ninguna prueba tipea la letra v) */ 223 else if (key == '&') key = '<'; /* el < de verdad (∠ en complejos) */ 224 else if (key == 1) key = K_UP; 225 else if (key == 2) key = K_RIGHT; 226 calc_key(c, key); 227 } 228 } 229 230 void selftest_app(void) 231 { 232 static Calc a, b; 233 static char buf[32000]; 234 calc_init(&a); 235 keys(&a, "1/3+1/6~"); 236 st_check(a.shown && !a.err && a.res.exact && a.res.x.a == 1 && a.res.x.d == 2, "app: 1/3+1/6 = 1/2"); 237 keys(&a, "*2~"); 238 st_check(!a.err && a.res.exact && a.res.x.a == 1 && a.res.x.d == 1, "app: Ans*2 = 1"); 239 keys(&a, "sqrt(8)~>A"); 240 keys(&a, "A^2~"); 241 st_check(!a.err && a.res.exact && a.res.x.a == 8 && a.res.x.d == 1, "app: STO A, A^2 = 8"); 242 keys(&a, "0.1+0.2~\t"); 243 st_check(a.want_dec, "app: S<->D"); 244 a.ang = ANG_RAD; 245 a.fmt.mode = FMT_FIX; a.fmt.n = 3; 246 int n = persist_save(&a, buf, sizeof buf); 247 calc_init(&b); 248 persist_load(&b, buf, n); 249 st_check(b.nh == a.nh && b.ang == ANG_RAD && b.fmt.mode == FMT_FIX && b.fmt.n == 3, "guardar/cargar: ajustes e historial (%d de %d)", b.nh, a.nh); 250 st_check(b.vars[VAR_A].exact && b.vars[VAR_A].x.b == 2 && b.vars[VAR_A].x.r == 2, "guardar/cargar: A = 2√2 exacto"); 251 char t1[256], t2[256]; 252 expr_to_text(&a.hist[0].in, t1, sizeof t1); 253 expr_to_text(&b.hist[0].in, t2, sizeof t2); 254 st_check(!strcmp(t1, t2), "guardar/cargar: historial %s = %s", t1, t2); 255 /* °′″ del resultado */ 256 calc_init(&a); 257 keys(&a, "1.51~'"); 258 static Expr d; 259 calc_result_expr(&a, &a.res, false, &d); 260 char ds[64] = ""; 261 fmt_plain(&a.res, &a.fmt, false, ds, sizeof ds); 262 { 263 Num tmpn; (void)tmpn; 264 char dd[64]; 265 int p = 0; 266 for (int i = 0; i < d.n; i++) { 267 int t = d.t[i]; 268 p = str_put(dd, sizeof dd, p, t == T_DEGS ? "°" : t == T_MIN ? "'" : t == T_SEC ? "\"" : (char[]){ (char)t, 0 }); 269 } 270 st_check(a.dms && !strcmp(dd, "1°30'36\""), "°′″: 1.51 = %s (esperaba 1°30'36\")", dd); 271 } 272 } 273 274 /* modos: ecuaciones, estadistica y programador, manejados con teclas como en la app */ 275 void selftest_modes(void) 276 { 277 static Calc c; 278 char b[128]; 279 calc_init(&c); 280 /* sistema 3x3: x+y+z=6, 2y+5z=-4, 2x+5y-z=27 -> 5, 3, -2 */ 281 keys(&c, "@2v~"); 282 keys(&c, "1~1~1~6~0~2~5~-4~2~5~-1~27~~"); 283 st_check(c.eq.nsol == 3, "sistema 3x3 resuelto"); 284 fmt_plain(&c.eq.sol[0].re, &c.fmt, false, b, sizeof b); 285 st_check(!strcmp(b, "5"), "sistema 3x3: x = %s (esperaba 5)", b); 286 fmt_plain(&c.eq.sol[2].re, &c.fmt, false, b, sizeof b); 287 st_check(!strcmp(b, "-2"), "sistema 3x3: z = %s (esperaba -2)", b); 288 /* x² - 2 = 0 -> ±√2 exacto */ 289 calc_init(&c); 290 keys(&c, "@2vv~1~0~-2~~"); 291 fmt_plain(&c.eq.sol[0].re, &c.fmt, false, b, sizeof b); 292 st_check(!strcmp(b, "√2"), "x²-2: x1 = %s (esperaba √2)", b); 293 /* x³ - 1 = 0 -> 1 y complejas -1/2 ± √3/2 i */ 294 calc_init(&c); 295 keys(&c, "@2vvv~1~0~0~-1~~"); 296 fmt_plain(&c.eq.sol[0].re, &c.fmt, false, b, sizeof b); 297 st_check(!strcmp(b, "1"), "x³-1: raiz real %s", b); 298 fmt_plain(&c.eq.sol[1].im, &c.fmt, false, b, sizeof b); 299 st_check(!strcmp(b, "√3/2") || !strcmp(b, "-√3/2"), "x³-1: parte imaginaria %s", b); 300 /* x³ - 2x - 5 = 0: raiz real 2.094551482 (sin raices racionales) */ 301 calc_init(&c); 302 keys(&c, "@2vvv~1~0~-2~-5~~"); 303 fmt_plain(&c.eq.sol[0].re, &c.fmt, false, b, sizeof b); 304 st_check(!strcmp(b, "2.094551482"), "x³-2x-5: %s (esperaba 2.094551482)", b); 305 /* SOLVE: cos(X) = X en radianes */ 306 calc_init(&c); 307 c.ang = ANG_RAD; 308 keys(&c, "@2vvvv~cos(x)=x~"); 309 fmt_plain(&c.eq.solve_x, &c.fmt, false, b, sizeof b); 310 st_check(!strcmp(b, "0.7390851332"), "SOLVE cos x = x: %s", b); 311 /* estadistica lineal: (1,2) (2,4) (3,6.1) */ 312 calc_init(&c); 313 keys(&c, "@6v~1~2~2~4~3~6.1~~"); 314 st_check(c.st.phase == 1 && c.st.rvalid, "estadística: regresión lineal"); 315 fmt_plain(&c.st.rb, &c.fmt, false, b, sizeof b); 316 st_check(!strcmp(b, "41/20"), "estadística: b = %s (esperaba 41/20)", b); 317 fmt_plain(&c.st.ra, &c.fmt, false, b, sizeof b); 318 st_check(!strcmp(b, "-1/15"), "estadística: a = %s (esperaba -1/15)", b); 319 /* ŷ(4) en Calcular */ 320 keys(&c, "<@1yhat(4)~"); 321 fmt_plain(&c.res, &c.fmt, false, b, sizeof b); 322 st_check(!strcmp(b, "122/15"), "ŷ(4) = %s (esperaba 122/15)", b); 323 /* programador: FF + 1 en hex, -1 en 32 bits, AND */ 324 calc_init(&c); 325 keys(&c, "@5\tFF+1~"); 326 st_check(!c.err && c.res.v.m && dec_cmp(c.res.v, dec_int(256)) == 0, "programador: FF+1 = 256"); 327 keys(&c, "<\t\t\t"); 328 keys(&c, "255 and 15~"); 329 st_check(!c.err && dec_cmp(c.res.v, dec_int(15)) == 0, "programador: 255 and 15 = 15"); 330 keys(&c, "7:2~"); 331 st_check(!c.err && dec_cmp(c.res.v, dec_int(3)) == 0, "programador: 7÷2 = 3"); 332 keys(&c, "2147483647+1~"); 333 st_check(!c.err && dec_cmp(c.res.v, dec_int(-2147483648ll)) == 0, "programador: desborde de 32 bits"); 334 335 /* complejos */ 336 static const struct { const char *in, *want; } CX[] = { 337 { "(3+4i)(1-2i)~", "11-2i" }, { "sqrt(-4)~", "2i" }, { "(1+i)/(1-i)~", "i" }, 338 { "2&60~", "1+√3i" }, { "|3+4i|~", "5" }, { "arg(1+i)~", "45" }, { "(1+i)^8~", "16" }, 339 { "i^2~", "-1" }, { "conjg(2-3i)~", "2+3i" }, { "1/i~", "-i" }, { "(2+i)^-1~", "2/5-1/5i" }, 340 { "sqrt(2i)~", "1+i" }, { "imag(5-7i)~", "-7" }, 341 }; 342 calc_init(&c); 343 keys(&c, "@7"); 344 for (size_t i = 0; i < sizeof CX / sizeof CX[0]; i++) { 345 keys(&c, "<"); 346 keys(&c, CX[i].in); 347 static Expr r; 348 char t[96]; 349 calc_res_expr(&c, &r); 350 /* texto lineal del resultado (√ y fracciones) */ 351 Num dummy; (void)dummy; 352 int p = 0; 353 t[0] = 0; 354 for (int k = 0; k < r.n; k++) { 355 int tk = r.t[k]; 356 const char *s2 = tk == T_SQRT ? "√" : tk == T_FRAC ? "" : tk == T_SEP ? "/" : tk == T_END ? "" : 357 tk == T_ANGLE ? "∠" : 0; 358 char ch[2] = { (char)tk, 0 }; 359 p = str_put(t, sizeof t, p, s2 ? s2 : ch); 360 } 361 st_check(!c.err && !strcmp(t, CX[i].want), "complejos: %s = %s (esperaba %s)", CX[i].in, c.err ? "error" : t, CX[i].want); 362 } 363 keys(&c, "<(1+i)^8~&"); 364 { 365 static Expr r; 366 calc_res_expr(&c, &r); 367 st_check(c.polar && r.n >= 3 && r.t[2] == T_ANGLE, "complejos: polar 16∠0"); 368 } 369 370 /* matrices: MatA = [2 1; 1 3], VctA = (1,2,3), VctB = (4,5,6) */ 371 calc_init(&c); 372 keys(&c, "@8=~~2~1~1~3~<"); 373 keys(&c, "=vvvv~\x01\x02v~1~2~3~<"); 374 keys(&c, "=v~\x01\x02v~4~5~6~<"); 375 st_check(c.mt.m[0].r == 2 && c.mt.v[0].c == 3 && c.mt.v[1].c == 3, "matrices: definidas MatA 2x2, VctA y VctB de 3"); 376 static const struct { const char *in, *want; } MX[] = { 377 { "det(A)~", "5" }, { "A^-1~", "3/5 -1/5 / -1/5 2/5" }, { "A*A~", "5 5 / 5 10" }, { "trn(A)~", "2 1 / 1 3" }, 378 { "A^3~", "15 20 / 20 35" }, { "dot(`A,`B)~", "32" }, { "cross(`A,`B)~", "-3 6 -3" }, { "|`A|~", "√14" }, 379 { "A*identity(2)-A~", "0 0 / 0 0" }, { "2A+A~", "6 3 / 3 9" }, 380 }; 381 for (size_t i = 0; i < sizeof MX / sizeof MX[0]; i++) { 382 keys(&c, "<"); 383 keys(&c, MX[i].in); 384 char t[160] = ""; 385 int p = 0; 386 const MVal *m = &c.mt.res; 387 for (int r = 0; r < m->r && !c.err; r++) { 388 if (r) p = str_put(t, sizeof t, p, " / "); 389 for (int j = 0; j < m->c; j++) { 390 char v[48]; 391 fmt_plain(mv_get(m, r, j), &c.fmt, false, v, sizeof v); 392 if (j) p = str_put(t, sizeof t, p, " "); 393 p = str_put(t, sizeof t, p, v); 394 } 395 } 396 st_check(!c.err && !strcmp(t, MX[i].want), "matrices: %s = %s (esperaba %s)", MX[i].in, c.err ? "error" : t, MX[i].want); 397 } 398 { 399 static Calc b2; 400 static char buf2[20000]; 401 int nb = persist_save(&c, buf2, sizeof buf2); 402 calc_init(&b2); 403 persist_load(&b2, buf2, nb); 404 st_check(b2.mt.m[0].r == 2 && b2.mt.v[1].c == 3 && dec_cmp(mv_get(&b2.mt.v[1], 0, 2)->v, dec_int(6)) == 0, 405 "matrices: guardar y cargar"); 406 } 407 }