2 ./gen can generate testcases using an mp lib
3 ./check can test an mp lib compared to the input
6 T.<rounding>.<inputs>.<outputs>.<outputerr>.<exceptflags>.
7 where . is a sequence of separators: " \t,(){}"
8 the T prefix and rounding mode are optional (default is RN),
9 so the following are all ok and equivalent input:
12 {RN, 1, 2.0, 0.1, INEXACT},
13 T(RN, 1, 2.0, 0.1, INEXACT)
15 for gen only rounding and inputs are required (the rest is discarded)
34 static int scan(const char *fmt, struct t *t, char *buf);
35 static int print(const char *fmt, struct t *t, char *buf, int n);
37 // TODO: many output, fmt->ulp
39 static int check(struct t *want, struct t *got, struct fun *f, float ulpthres, float *abserr);
43 int (*mpf)(struct t*);
46 #define T(f,t) {#f, mp##f, #t},
47 #include "functions.h"
51 int main(int argc, char *argv[])
60 double ulpthres = 1.0;
65 p = strrchr(argv[0], '/');
70 checkmode = strcmp(p, "check") == 0;
72 fprintf(stderr, "%s func%s\n", argv[0], checkmode ? " ulpthres" : "");
75 if (argc > 2 && checkmode) {
76 ulpthres = strtod(argv[2], &p);
78 fprintf(stderr, "invalid ulperr %s\n", argv[2]);
82 for (i = 0; i < sizeof fun/sizeof *fun; i++)
83 if (strcmp(fun[i].name, argv[1]) == 0) {
88 fprintf(stderr, "unknown func: %s\n", argv[1]);
91 for (i = 1; fgets(buf, sizeof buf, stdin); i++) {
93 if (*buf == 0 || *buf == '\n')
95 memset(&t, 0, sizeof t);
96 if (scan(f->fmt, &t, buf))
97 fprintf(stderr, "error scan %s, line %d\n", f->name, i);
100 fprintf(stderr, "error mpf %s, line %d\n", f->name, i);
102 if (check(&tread, &t, f, ulpthres, &abserr)) {
103 print(f->fmt, &tread, buf, sizeof buf);
105 // print(f->fmt, &t, buf, sizeof buf);
106 // fputs(buf, stdout);
108 if (abserr > maxerr) {
113 if (print(f->fmt, &t, buf, sizeof buf))
114 fprintf(stderr, "error fmt %s, line %d\n", f->name, i);
118 if (checkmode && maxerr) {
119 printf("// maxerr: %f, ", maxerr);
120 print(f->fmt, &terr, buf, sizeof buf);
126 static int check(struct t *want, struct t *got, struct fun *f, float ulpthres, float *abserr)
129 int m = INEXACT|UNDERFLOW; // TODO: dont check inexact and underflow for now
131 if ((got->e|m) != (want->e|m)) {
132 fprintf(stdout, "//%s %s(%La,%La)==%La except: want %s",
133 rstr(want->r), f->name, want->x, want->x2, want->y, estr(want->e));
134 fprintf(stdout, " got %s\n", estr(got->e));
137 if (isnan(got->y) && isnan(want->y))
139 if (got->y != want->y || signbit(got->y) != signbit(want->y)) {
144 p = strchr(f->fmt, '_');
157 d = scalbnl(got->y - want->y, -n);
158 *abserr = fabsf(d + want->dy);
159 if (*abserr <= ulpthres)
161 fprintf(stdout, "//%s %s(%La,%La) want %La got %La ulperr %.3f = %a + %a\n",
162 rstr(want->r), f->name, want->x, want->x2, want->y, got->y, d + want->dy, d, want->dy);
168 // scan discards suffixes, this may cause rounding issues (eg scanning 0.1f as long double)
169 static int scan1(long double *x, char *s, int fmt)
175 if (sscanf(s, "%lf", &d) != 1)
178 } else if (fmt == 'f') {
179 if (sscanf(s, "%f", &f) != 1)
182 } else if (fmt == 'l') {
183 return sscanf(s, "%Lf", x) != 1;
189 static int scan(const char *fmt, struct t *t, char *buf)
197 buf = skipstr(buf, "T \t\r\n,(){}");
198 n = splitstr(a, sizeof a/sizeof *a, buf, " \t\r\n,(){}");
201 if (a[0][0] == 'R') {
202 if (rconv(&t->r, a[i++]))
211 for (; *fmt && *fmt != '_'; fmt++) {
215 t->i = strtoll(a[i++], &end, 0);
218 } else if (*fmt == 'd' || *fmt == 'f' || *fmt == 'l') {
219 if (scan1(b[j++], a[i++], *fmt))
231 for (; *fmt && i < n && j < sizeof b/sizeof *b; fmt++) {
233 t->i = strtoll(a[i++], &end, 0);
236 } else if (*fmt == 'd' || *fmt == 'f' || *fmt == 'l') {
237 if (scan1(b[j++], a[i++], *fmt))
239 if (i < n && scan1(b[j++], a[i++], 'f'))
251 /* assume strlen(old) == strlen(new) */
252 static void replace(char *buf, char *old, char *new)
257 while ((p = strstr(p, old)))
261 static void fixl(char *buf)
263 replace(buf, "-infL", " -inf");
264 replace(buf, "infL", " inf");
265 replace(buf, "-nanL", " -nan");
266 replace(buf, "nanL", " nan");
269 static int print1(char *buf, int n, long double x, int fmt)
274 k = snprintf(buf, n, ",%24a", (double)x);
276 k = snprintf(buf, n, ",%16a", (double)x);
277 else if (fmt == 'l') {
278 #if LDBL_MANT_DIG == 53
279 k = snprintf(buf, n, ",%24a", (double)x);
280 #elif LDBL_MANT_DIG == 64
281 k = snprintf(buf, n, ",%30LaL", x);
289 static int print(const char *fmt, struct t *t, char *buf, int n)
294 k = snprintf(buf, n, "T(%s", rstr(t->r));
303 for (; *fmt; fmt++) {
314 k = snprintf(buf, n, ", %11lld", t->i);
320 if (i >= sizeof a/sizeof *a)
322 k = print1(buf, n, a[i++], *fmt);
328 k = print1(buf, n, a[i++], 'f');
336 k = snprintf(buf, n, ", %s)\n", estr(t->e));