| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "gen.h" |
| |
| static int scan(const char *fmt, struct t *t, char *buf); |
| static int print(const char *fmt, struct t *t, char *buf, int n); |
| |
| |
| struct fun; |
| static int check(struct t *want, struct t *got, struct fun *f, float ulpthres, float *abserr); |
| |
| struct fun { |
| char *name; |
| int (*mpf)(struct t*); |
| char *fmt; |
| } fun[] = { |
| #define T(f,t) {#f, mp##f, #t}, |
| #include "functions.h" |
| #undef T |
| }; |
| |
| int main(int argc, char *argv[]) |
| { |
| char buf[512]; |
| char *p; |
| int checkmode; |
| int i; |
| struct t t; |
| struct t tread; |
| struct fun *f = 0; |
| double ulpthres = 1.0; |
| float maxerr = 0; |
| float abserr; |
| struct t terr; |
| |
| p = strrchr(argv[0], '/'); |
| if (!p) |
| p = argv[0]; |
| else |
| p++; |
| checkmode = strcmp(p, "check") == 0; |
| if (argc < 2) { |
| fprintf(stderr, "%s func%s\n", argv[0], checkmode ? " ulpthres" : ""); |
| return 1; |
| } |
| if (argc > 2 && checkmode) { |
| ulpthres = strtod(argv[2], &p); |
| if (*p) { |
| fprintf(stderr, "invalid ulperr %s\n", argv[2]); |
| return 1; |
| } |
| } |
| for (i = 0; i < sizeof fun/sizeof *fun; i++) |
| if (strcmp(fun[i].name, argv[1]) == 0) { |
| f = fun + i; |
| break; |
| } |
| if (f == 0) { |
| fprintf(stderr, "unknown func: %s\n", argv[1]); |
| return 1; |
| } |
| for (i = 1; fgets(buf, sizeof buf, stdin); i++) { |
| dropcomm(buf); |
| if (*buf == 0 || *buf == '\n') |
| continue; |
| memset(&t, 0, sizeof t); |
| if (scan(f->fmt, &t, buf)) |
| fprintf(stderr, "error scan %s, line %d\n", f->name, i); |
| tread = t; |
| if (f->mpf(&t)) |
| fprintf(stderr, "error mpf %s, line %d\n", f->name, i); |
| if (checkmode) { |
| if (check(&tread, &t, f, ulpthres, &abserr)) { |
| print(f->fmt, &tread, buf, sizeof buf); |
| fputs(buf, stdout); |
| |
| |
| } |
| if (abserr > maxerr) { |
| maxerr = abserr; |
| terr = tread; |
| } |
| } else { |
| if (print(f->fmt, &t, buf, sizeof buf)) |
| fprintf(stderr, "error fmt %s, line %d\n", f->name, i); |
| fputs(buf, stdout); |
| } |
| } |
| if (checkmode && maxerr) { |
| printf("// maxerr: %f, ", maxerr); |
| print(f->fmt, &terr, buf, sizeof buf); |
| fputs(buf, stdout); |
| } |
| return 0; |
| } |
| |
| static int check(struct t *want, struct t *got, struct fun *f, float ulpthres, float *abserr) |
| { |
| int err = 0; |
| int m = INEXACT|UNDERFLOW; |
| |
| if ((got->e|m) != (want->e|m)) { |
| fprintf(stdout, "//%s %s(%La,%La)==%La except: want %s", |
| rstr(want->r), f->name, want->x, want->x2, want->y, estr(want->e)); |
| fprintf(stdout, " got %s\n", estr(got->e)); |
| err++; |
| } |
| if (isnan(got->y) && isnan(want->y)) |
| return err; |
| if (got->y != want->y || signbit(got->y) != signbit(want->y)) { |
| char *p; |
| int n; |
| float d; |
| |
| p = strchr(f->fmt, '_'); |
| if (!p) |
| return -1; |
| p++; |
| if (*p == 'd') |
| n = eulp(want->y); |
| else if (*p == 'f') |
| n = eulpf(want->y); |
| else if (*p == 'l') |
| n = eulpl(want->y); |
| else |
| return -1; |
| |
| d = scalbnl(got->y - want->y, -n); |
| *abserr = fabsf(d + want->dy); |
| if (*abserr <= ulpthres) |
| return err; |
| fprintf(stdout, "//%s %s(%La,%La) want %La got %La ulperr %.3f = %a + %a\n", |
| rstr(want->r), f->name, want->x, want->x2, want->y, got->y, d + want->dy, d, want->dy); |
| err++; |
| } |
| return err; |
| } |
| |
| |
| static int scan1(long double *x, char *s, int fmt) |
| { |
| double d; |
| float f; |
| |
| if (fmt == 'd') { |
| if (sscanf(s, "%lf", &d) != 1) |
| return -1; |
| *x = d; |
| } else if (fmt == 'f') { |
| if (sscanf(s, "%f", &f) != 1) |
| return -1; |
| *x = f; |
| } else if (fmt == 'l') { |
| return sscanf(s, "%Lf", x) != 1; |
| } else |
| return -1; |
| return 0; |
| } |
| |
| static int scan(const char *fmt, struct t *t, char *buf) |
| { |
| char *a[20]; |
| long double *b[4]; |
| long double dy, dy2; |
| char *end; |
| int n, i=0, j=0; |
| |
| buf = skipstr(buf, "T \t\r\n,(){}"); |
| n = splitstr(a, sizeof a/sizeof *a, buf, " \t\r\n,(){}"); |
| if (n <= 0) |
| return -1; |
| if (a[0][0] == 'R') { |
| if (rconv(&t->r, a[i++])) |
| return -1; |
| } else |
| t->r = RN; |
| |
| b[0] = &t->x; |
| b[1] = &t->x2; |
| b[2] = &t->x3; |
| b[3] = 0; |
| for (; *fmt && *fmt != '_'; fmt++) { |
| if (i >= n) |
| return -1; |
| if (*fmt == 'i') { |
| t->i = strtoll(a[i++], &end, 0); |
| if (*end) |
| return -1; |
| } else if (*fmt == 'd' || *fmt == 'f' || *fmt == 'l') { |
| if (scan1(b[j++], a[i++], *fmt)) |
| return -1; |
| } else |
| return -1; |
| } |
| |
| b[0] = &t->y; |
| b[1] = &dy; |
| b[2] = &t->y2; |
| b[3] = &dy2; |
| j = 0; |
| fmt++; |
| for (; *fmt && i < n && j < sizeof b/sizeof *b; fmt++) { |
| if (*fmt == 'i') { |
| t->i = strtoll(a[i++], &end, 0); |
| if (*end) |
| return -1; |
| } else if (*fmt == 'd' || *fmt == 'f' || *fmt == 'l') { |
| if (scan1(b[j++], a[i++], *fmt)) |
| return -1; |
| if (i < n && scan1(b[j++], a[i++], 'f')) |
| return -1; |
| } else |
| return -1; |
| } |
| t->dy = dy; |
| t->dy2 = dy2; |
| if (i < n) |
| econv(&t->e, a[i]); |
| return 0; |
| } |
| |
| |
| static void replace(char *buf, char *old, char *new) |
| { |
| int n = strlen(new); |
| char *p = buf; |
| |
| while ((p = strstr(p, old))) |
| memcpy(p, new, n); |
| } |
| |
| static void fixl(char *buf) |
| { |
| replace(buf, "-infL", " -inf"); |
| replace(buf, "infL", " inf"); |
| replace(buf, "-nanL", " -nan"); |
| replace(buf, "nanL", " nan"); |
| } |
| |
| static int print1(char *buf, int n, long double x, int fmt) |
| { |
| int k; |
| |
| if (fmt == 'd') |
| k = snprintf(buf, n, ",%24a", (double)x); |
| else if (fmt == 'f') |
| k = snprintf(buf, n, ",%16a", (double)x); |
| else if (fmt == 'l') { |
| #if LDBL_MANT_DIG == 53 |
| k = snprintf(buf, n, ",%24a", (double)x); |
| #elif LDBL_MANT_DIG == 64 |
| k = snprintf(buf, n, ",%30LaL", x); |
| fixl(buf); |
| #endif |
| } else |
| k = -1; |
| return k; |
| } |
| |
| static int print(const char *fmt, struct t *t, char *buf, int n) |
| { |
| long double a[4]; |
| int k, i=0, out=0; |
| |
| k = snprintf(buf, n, "T(%s", rstr(t->r)); |
| if (k < 0 || k >= n) |
| return -1; |
| n -= k; |
| buf += k; |
| |
| a[0] = t->x; |
| a[1] = t->x2; |
| a[2] = t->x3; |
| for (; *fmt; fmt++) { |
| if (*fmt == '_') { |
| a[0] = t->y; |
| a[1] = t->dy; |
| a[2] = t->y2; |
| a[3] = t->dy2; |
| i = 0; |
| out = 1; |
| continue; |
| } |
| if (*fmt == 'i') { |
| k = snprintf(buf, n, ", %11lld", t->i); |
| if (k < 0 || k >= n) |
| return -1; |
| n -= k; |
| buf += k; |
| } else { |
| if (i >= sizeof a/sizeof *a) |
| return -1; |
| k = print1(buf, n, a[i++], *fmt); |
| if (k < 0 || k >= n) |
| return -1; |
| n -= k; |
| buf += k; |
| if (out) { |
| k = print1(buf, n, a[i++], 'f'); |
| if (k < 0 || k >= n) |
| return -1; |
| n -= k; |
| buf += k; |
| } |
| } |
| } |
| k = snprintf(buf, n, ", %s)\n", estr(t->e)); |
| if (k < 0 || k >= n) |
| return -1; |
| return 0; |
| } |