1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci./gen can generate testcases using an mp lib 3570af302Sopenharmony_ci./check can test an mp lib compared to the input 4570af302Sopenharmony_ci 5570af302Sopenharmony_ciinput format: 6570af302Sopenharmony_ciT.<rounding>.<inputs>.<outputs>.<outputerr>.<exceptflags>. 7570af302Sopenharmony_ciwhere . is a sequence of separators: " \t,(){}" 8570af302Sopenharmony_cithe T prefix and rounding mode are optional (default is RN), 9570af302Sopenharmony_ciso the following are all ok and equivalent input: 10570af302Sopenharmony_ci 11570af302Sopenharmony_ci 1 2.0 0.1 INEXACT 12570af302Sopenharmony_ci {RN, 1, 2.0, 0.1, INEXACT}, 13570af302Sopenharmony_ci T(RN, 1, 2.0, 0.1, INEXACT) 14570af302Sopenharmony_ci 15570af302Sopenharmony_cifor gen only rounding and inputs are required (the rest is discarded) 16570af302Sopenharmony_ci 17570af302Sopenharmony_cigen: 18570af302Sopenharmony_ci s = getline() 19570af302Sopenharmony_ci x = scan(s) 20570af302Sopenharmony_ci xy = mpfunc(x) 21570af302Sopenharmony_ci print(xy) 22570af302Sopenharmony_cicheck: 23570af302Sopenharmony_ci s = getline() 24570af302Sopenharmony_ci xy = scan(s) 25570af302Sopenharmony_ci xy' = mpfunc(x) 26570af302Sopenharmony_ci check(xy, xy') 27570af302Sopenharmony_ci*/ 28570af302Sopenharmony_ci 29570af302Sopenharmony_ci#include <stdlib.h> 30570af302Sopenharmony_ci#include <stdio.h> 31570af302Sopenharmony_ci#include <string.h> 32570af302Sopenharmony_ci#include "gen.h" 33570af302Sopenharmony_ci 34570af302Sopenharmony_cistatic int scan(const char *fmt, struct t *t, char *buf); 35570af302Sopenharmony_cistatic int print(const char *fmt, struct t *t, char *buf, int n); 36570af302Sopenharmony_ci 37570af302Sopenharmony_ci// TODO: many output, fmt->ulp 38570af302Sopenharmony_cistruct fun; 39570af302Sopenharmony_cistatic int check(struct t *want, struct t *got, struct fun *f, float ulpthres, float *abserr); 40570af302Sopenharmony_ci 41570af302Sopenharmony_cistruct fun { 42570af302Sopenharmony_ci char *name; 43570af302Sopenharmony_ci int (*mpf)(struct t*); 44570af302Sopenharmony_ci char *fmt; 45570af302Sopenharmony_ci} fun[] = { 46570af302Sopenharmony_ci#define T(f,t) {#f, mp##f, #t}, 47570af302Sopenharmony_ci#include "functions.h" 48570af302Sopenharmony_ci#undef T 49570af302Sopenharmony_ci}; 50570af302Sopenharmony_ci 51570af302Sopenharmony_ciint main(int argc, char *argv[]) 52570af302Sopenharmony_ci{ 53570af302Sopenharmony_ci char buf[512]; 54570af302Sopenharmony_ci char *p; 55570af302Sopenharmony_ci int checkmode; 56570af302Sopenharmony_ci int i; 57570af302Sopenharmony_ci struct t t; 58570af302Sopenharmony_ci struct t tread; 59570af302Sopenharmony_ci struct fun *f = 0; 60570af302Sopenharmony_ci double ulpthres = 1.0; 61570af302Sopenharmony_ci float maxerr = 0; 62570af302Sopenharmony_ci float abserr; 63570af302Sopenharmony_ci struct t terr; 64570af302Sopenharmony_ci 65570af302Sopenharmony_ci p = strrchr(argv[0], '/'); 66570af302Sopenharmony_ci if (!p) 67570af302Sopenharmony_ci p = argv[0]; 68570af302Sopenharmony_ci else 69570af302Sopenharmony_ci p++; 70570af302Sopenharmony_ci checkmode = strcmp(p, "check") == 0; 71570af302Sopenharmony_ci if (argc < 2) { 72570af302Sopenharmony_ci fprintf(stderr, "%s func%s\n", argv[0], checkmode ? " ulpthres" : ""); 73570af302Sopenharmony_ci return 1; 74570af302Sopenharmony_ci } 75570af302Sopenharmony_ci if (argc > 2 && checkmode) { 76570af302Sopenharmony_ci ulpthres = strtod(argv[2], &p); 77570af302Sopenharmony_ci if (*p) { 78570af302Sopenharmony_ci fprintf(stderr, "invalid ulperr %s\n", argv[2]); 79570af302Sopenharmony_ci return 1; 80570af302Sopenharmony_ci } 81570af302Sopenharmony_ci } 82570af302Sopenharmony_ci for (i = 0; i < sizeof fun/sizeof *fun; i++) 83570af302Sopenharmony_ci if (strcmp(fun[i].name, argv[1]) == 0) { 84570af302Sopenharmony_ci f = fun + i; 85570af302Sopenharmony_ci break; 86570af302Sopenharmony_ci } 87570af302Sopenharmony_ci if (f == 0) { 88570af302Sopenharmony_ci fprintf(stderr, "unknown func: %s\n", argv[1]); 89570af302Sopenharmony_ci return 1; 90570af302Sopenharmony_ci } 91570af302Sopenharmony_ci for (i = 1; fgets(buf, sizeof buf, stdin); i++) { 92570af302Sopenharmony_ci dropcomm(buf); 93570af302Sopenharmony_ci if (*buf == 0 || *buf == '\n') 94570af302Sopenharmony_ci continue; 95570af302Sopenharmony_ci memset(&t, 0, sizeof t); 96570af302Sopenharmony_ci if (scan(f->fmt, &t, buf)) 97570af302Sopenharmony_ci fprintf(stderr, "error scan %s, line %d\n", f->name, i); 98570af302Sopenharmony_ci tread = t; 99570af302Sopenharmony_ci if (f->mpf(&t)) 100570af302Sopenharmony_ci fprintf(stderr, "error mpf %s, line %d\n", f->name, i); 101570af302Sopenharmony_ci if (checkmode) { 102570af302Sopenharmony_ci if (check(&tread, &t, f, ulpthres, &abserr)) { 103570af302Sopenharmony_ci print(f->fmt, &tread, buf, sizeof buf); 104570af302Sopenharmony_ci fputs(buf, stdout); 105570af302Sopenharmony_ci// print(f->fmt, &t, buf, sizeof buf); 106570af302Sopenharmony_ci// fputs(buf, stdout); 107570af302Sopenharmony_ci } 108570af302Sopenharmony_ci if (abserr > maxerr) { 109570af302Sopenharmony_ci maxerr = abserr; 110570af302Sopenharmony_ci terr = tread; 111570af302Sopenharmony_ci } 112570af302Sopenharmony_ci } else { 113570af302Sopenharmony_ci if (print(f->fmt, &t, buf, sizeof buf)) 114570af302Sopenharmony_ci fprintf(stderr, "error fmt %s, line %d\n", f->name, i); 115570af302Sopenharmony_ci fputs(buf, stdout); 116570af302Sopenharmony_ci } 117570af302Sopenharmony_ci } 118570af302Sopenharmony_ci if (checkmode && maxerr) { 119570af302Sopenharmony_ci printf("// maxerr: %f, ", maxerr); 120570af302Sopenharmony_ci print(f->fmt, &terr, buf, sizeof buf); 121570af302Sopenharmony_ci fputs(buf, stdout); 122570af302Sopenharmony_ci } 123570af302Sopenharmony_ci return 0; 124570af302Sopenharmony_ci} 125570af302Sopenharmony_ci 126570af302Sopenharmony_cistatic int check(struct t *want, struct t *got, struct fun *f, float ulpthres, float *abserr) 127570af302Sopenharmony_ci{ 128570af302Sopenharmony_ci int err = 0; 129570af302Sopenharmony_ci int m = INEXACT|UNDERFLOW; // TODO: dont check inexact and underflow for now 130570af302Sopenharmony_ci 131570af302Sopenharmony_ci if ((got->e|m) != (want->e|m)) { 132570af302Sopenharmony_ci fprintf(stdout, "//%s %s(%La,%La)==%La except: want %s", 133570af302Sopenharmony_ci rstr(want->r), f->name, want->x, want->x2, want->y, estr(want->e)); 134570af302Sopenharmony_ci fprintf(stdout, " got %s\n", estr(got->e)); 135570af302Sopenharmony_ci err++; 136570af302Sopenharmony_ci } 137570af302Sopenharmony_ci if (isnan(got->y) && isnan(want->y)) 138570af302Sopenharmony_ci return err; 139570af302Sopenharmony_ci if (got->y != want->y || signbit(got->y) != signbit(want->y)) { 140570af302Sopenharmony_ci char *p; 141570af302Sopenharmony_ci int n; 142570af302Sopenharmony_ci float d; 143570af302Sopenharmony_ci 144570af302Sopenharmony_ci p = strchr(f->fmt, '_'); 145570af302Sopenharmony_ci if (!p) 146570af302Sopenharmony_ci return -1; 147570af302Sopenharmony_ci p++; 148570af302Sopenharmony_ci if (*p == 'd') 149570af302Sopenharmony_ci n = eulp(want->y); 150570af302Sopenharmony_ci else if (*p == 'f') 151570af302Sopenharmony_ci n = eulpf(want->y); 152570af302Sopenharmony_ci else if (*p == 'l') 153570af302Sopenharmony_ci n = eulpl(want->y); 154570af302Sopenharmony_ci else 155570af302Sopenharmony_ci return -1; 156570af302Sopenharmony_ci 157570af302Sopenharmony_ci d = scalbnl(got->y - want->y, -n); 158570af302Sopenharmony_ci *abserr = fabsf(d + want->dy); 159570af302Sopenharmony_ci if (*abserr <= ulpthres) 160570af302Sopenharmony_ci return err; 161570af302Sopenharmony_ci fprintf(stdout, "//%s %s(%La,%La) want %La got %La ulperr %.3f = %a + %a\n", 162570af302Sopenharmony_ci rstr(want->r), f->name, want->x, want->x2, want->y, got->y, d + want->dy, d, want->dy); 163570af302Sopenharmony_ci err++; 164570af302Sopenharmony_ci } 165570af302Sopenharmony_ci return err; 166570af302Sopenharmony_ci} 167570af302Sopenharmony_ci 168570af302Sopenharmony_ci// scan discards suffixes, this may cause rounding issues (eg scanning 0.1f as long double) 169570af302Sopenharmony_cistatic int scan1(long double *x, char *s, int fmt) 170570af302Sopenharmony_ci{ 171570af302Sopenharmony_ci double d; 172570af302Sopenharmony_ci float f; 173570af302Sopenharmony_ci 174570af302Sopenharmony_ci if (fmt == 'd') { 175570af302Sopenharmony_ci if (sscanf(s, "%lf", &d) != 1) 176570af302Sopenharmony_ci return -1; 177570af302Sopenharmony_ci *x = d; 178570af302Sopenharmony_ci } else if (fmt == 'f') { 179570af302Sopenharmony_ci if (sscanf(s, "%f", &f) != 1) 180570af302Sopenharmony_ci return -1; 181570af302Sopenharmony_ci *x = f; 182570af302Sopenharmony_ci } else if (fmt == 'l') { 183570af302Sopenharmony_ci return sscanf(s, "%Lf", x) != 1; 184570af302Sopenharmony_ci } else 185570af302Sopenharmony_ci return -1; 186570af302Sopenharmony_ci return 0; 187570af302Sopenharmony_ci} 188570af302Sopenharmony_ci 189570af302Sopenharmony_cistatic int scan(const char *fmt, struct t *t, char *buf) 190570af302Sopenharmony_ci{ 191570af302Sopenharmony_ci char *a[20]; 192570af302Sopenharmony_ci long double *b[4]; 193570af302Sopenharmony_ci long double dy, dy2; 194570af302Sopenharmony_ci char *end; 195570af302Sopenharmony_ci int n, i=0, j=0; 196570af302Sopenharmony_ci 197570af302Sopenharmony_ci buf = skipstr(buf, "T \t\r\n,(){}"); 198570af302Sopenharmony_ci n = splitstr(a, sizeof a/sizeof *a, buf, " \t\r\n,(){}"); 199570af302Sopenharmony_ci if (n <= 0) 200570af302Sopenharmony_ci return -1; 201570af302Sopenharmony_ci if (a[0][0] == 'R') { 202570af302Sopenharmony_ci if (rconv(&t->r, a[i++])) 203570af302Sopenharmony_ci return -1; 204570af302Sopenharmony_ci } else 205570af302Sopenharmony_ci t->r = RN; 206570af302Sopenharmony_ci 207570af302Sopenharmony_ci b[0] = &t->x; 208570af302Sopenharmony_ci b[1] = &t->x2; 209570af302Sopenharmony_ci b[2] = &t->x3; 210570af302Sopenharmony_ci b[3] = 0; 211570af302Sopenharmony_ci for (; *fmt && *fmt != '_'; fmt++) { 212570af302Sopenharmony_ci if (i >= n) 213570af302Sopenharmony_ci return -1; 214570af302Sopenharmony_ci if (*fmt == 'i') { 215570af302Sopenharmony_ci t->i = strtoll(a[i++], &end, 0); 216570af302Sopenharmony_ci if (*end) 217570af302Sopenharmony_ci return -1; 218570af302Sopenharmony_ci } else if (*fmt == 'd' || *fmt == 'f' || *fmt == 'l') { 219570af302Sopenharmony_ci if (scan1(b[j++], a[i++], *fmt)) 220570af302Sopenharmony_ci return -1; 221570af302Sopenharmony_ci } else 222570af302Sopenharmony_ci return -1; 223570af302Sopenharmony_ci } 224570af302Sopenharmony_ci 225570af302Sopenharmony_ci b[0] = &t->y; 226570af302Sopenharmony_ci b[1] = &dy; 227570af302Sopenharmony_ci b[2] = &t->y2; 228570af302Sopenharmony_ci b[3] = &dy2; 229570af302Sopenharmony_ci j = 0; 230570af302Sopenharmony_ci fmt++; 231570af302Sopenharmony_ci for (; *fmt && i < n && j < sizeof b/sizeof *b; fmt++) { 232570af302Sopenharmony_ci if (*fmt == 'i') { 233570af302Sopenharmony_ci t->i = strtoll(a[i++], &end, 0); 234570af302Sopenharmony_ci if (*end) 235570af302Sopenharmony_ci return -1; 236570af302Sopenharmony_ci } else if (*fmt == 'd' || *fmt == 'f' || *fmt == 'l') { 237570af302Sopenharmony_ci if (scan1(b[j++], a[i++], *fmt)) 238570af302Sopenharmony_ci return -1; 239570af302Sopenharmony_ci if (i < n && scan1(b[j++], a[i++], 'f')) 240570af302Sopenharmony_ci return -1; 241570af302Sopenharmony_ci } else 242570af302Sopenharmony_ci return -1; 243570af302Sopenharmony_ci } 244570af302Sopenharmony_ci t->dy = dy; 245570af302Sopenharmony_ci t->dy2 = dy2; 246570af302Sopenharmony_ci if (i < n) 247570af302Sopenharmony_ci econv(&t->e, a[i]); 248570af302Sopenharmony_ci return 0; 249570af302Sopenharmony_ci} 250570af302Sopenharmony_ci 251570af302Sopenharmony_ci/* assume strlen(old) == strlen(new) */ 252570af302Sopenharmony_cistatic void replace(char *buf, char *old, char *new) 253570af302Sopenharmony_ci{ 254570af302Sopenharmony_ci int n = strlen(new); 255570af302Sopenharmony_ci char *p = buf; 256570af302Sopenharmony_ci 257570af302Sopenharmony_ci while ((p = strstr(p, old))) 258570af302Sopenharmony_ci memcpy(p, new, n); 259570af302Sopenharmony_ci} 260570af302Sopenharmony_ci 261570af302Sopenharmony_cistatic void fixl(char *buf) 262570af302Sopenharmony_ci{ 263570af302Sopenharmony_ci replace(buf, "-infL", " -inf"); 264570af302Sopenharmony_ci replace(buf, "infL", " inf"); 265570af302Sopenharmony_ci replace(buf, "-nanL", " -nan"); 266570af302Sopenharmony_ci replace(buf, "nanL", " nan"); 267570af302Sopenharmony_ci} 268570af302Sopenharmony_ci 269570af302Sopenharmony_cistatic int print1(char *buf, int n, long double x, int fmt) 270570af302Sopenharmony_ci{ 271570af302Sopenharmony_ci int k; 272570af302Sopenharmony_ci 273570af302Sopenharmony_ci if (fmt == 'd') 274570af302Sopenharmony_ci k = snprintf(buf, n, ",%24a", (double)x); 275570af302Sopenharmony_ci else if (fmt == 'f') 276570af302Sopenharmony_ci k = snprintf(buf, n, ",%16a", (double)x); 277570af302Sopenharmony_ci else if (fmt == 'l') { 278570af302Sopenharmony_ci#if LDBL_MANT_DIG == 53 279570af302Sopenharmony_ci k = snprintf(buf, n, ",%24a", (double)x); 280570af302Sopenharmony_ci#elif LDBL_MANT_DIG == 64 281570af302Sopenharmony_ci k = snprintf(buf, n, ",%30LaL", x); 282570af302Sopenharmony_ci fixl(buf); 283570af302Sopenharmony_ci#endif 284570af302Sopenharmony_ci } else 285570af302Sopenharmony_ci k = -1; 286570af302Sopenharmony_ci return k; 287570af302Sopenharmony_ci} 288570af302Sopenharmony_ci 289570af302Sopenharmony_cistatic int print(const char *fmt, struct t *t, char *buf, int n) 290570af302Sopenharmony_ci{ 291570af302Sopenharmony_ci long double a[4]; 292570af302Sopenharmony_ci int k, i=0, out=0; 293570af302Sopenharmony_ci 294570af302Sopenharmony_ci k = snprintf(buf, n, "T(%s", rstr(t->r)); 295570af302Sopenharmony_ci if (k < 0 || k >= n) 296570af302Sopenharmony_ci return -1; 297570af302Sopenharmony_ci n -= k; 298570af302Sopenharmony_ci buf += k; 299570af302Sopenharmony_ci 300570af302Sopenharmony_ci a[0] = t->x; 301570af302Sopenharmony_ci a[1] = t->x2; 302570af302Sopenharmony_ci a[2] = t->x3; 303570af302Sopenharmony_ci for (; *fmt; fmt++) { 304570af302Sopenharmony_ci if (*fmt == '_') { 305570af302Sopenharmony_ci a[0] = t->y; 306570af302Sopenharmony_ci a[1] = t->dy; 307570af302Sopenharmony_ci a[2] = t->y2; 308570af302Sopenharmony_ci a[3] = t->dy2; 309570af302Sopenharmony_ci i = 0; 310570af302Sopenharmony_ci out = 1; 311570af302Sopenharmony_ci continue; 312570af302Sopenharmony_ci } 313570af302Sopenharmony_ci if (*fmt == 'i') { 314570af302Sopenharmony_ci k = snprintf(buf, n, ", %11lld", t->i); 315570af302Sopenharmony_ci if (k < 0 || k >= n) 316570af302Sopenharmony_ci return -1; 317570af302Sopenharmony_ci n -= k; 318570af302Sopenharmony_ci buf += k; 319570af302Sopenharmony_ci } else { 320570af302Sopenharmony_ci if (i >= sizeof a/sizeof *a) 321570af302Sopenharmony_ci return -1; 322570af302Sopenharmony_ci k = print1(buf, n, a[i++], *fmt); 323570af302Sopenharmony_ci if (k < 0 || k >= n) 324570af302Sopenharmony_ci return -1; 325570af302Sopenharmony_ci n -= k; 326570af302Sopenharmony_ci buf += k; 327570af302Sopenharmony_ci if (out) { 328570af302Sopenharmony_ci k = print1(buf, n, a[i++], 'f'); 329570af302Sopenharmony_ci if (k < 0 || k >= n) 330570af302Sopenharmony_ci return -1; 331570af302Sopenharmony_ci n -= k; 332570af302Sopenharmony_ci buf += k; 333570af302Sopenharmony_ci } 334570af302Sopenharmony_ci } 335570af302Sopenharmony_ci } 336570af302Sopenharmony_ci k = snprintf(buf, n, ", %s)\n", estr(t->e)); 337570af302Sopenharmony_ci if (k < 0 || k >= n) 338570af302Sopenharmony_ci return -1; 339570af302Sopenharmony_ci return 0; 340570af302Sopenharmony_ci} 341