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
));