| #include <u.h> |
| #include <libc.h> |
| #include <stdio.h> |
| |
| /* |
| * try all combination of flags and float conversions |
| * with some different widths & precisions |
| */ |
| |
| #define Njust 2 |
| #define Nplus 3 |
| #define Nalt 2 |
| #define Nzero 2 |
| #define Nspec 5 |
| #define Nwidth 5 |
| #define Nprec 5 |
| |
| static double fmtvals[] = { |
| 3.1415925535897932e15, |
| 3.1415925535897932e14, |
| 3.1415925535897932e13, |
| 3.1415925535897932e12, |
| 3.1415925535897932e11, |
| 3.1415925535897932e10, |
| 3.1415925535897932e9, |
| 3.1415925535897932e8, |
| 3.1415925535897932e7, |
| 3.1415925535897932e6, |
| 3.1415925535897932e5, |
| 3.1415925535897932e4, |
| 3.1415925535897932e3, |
| 3.1415925535897932e2, |
| 3.1415925535897932e1, |
| 3.1415925535897932e0, |
| 3.1415925535897932e-1, |
| 3.1415925535897932e-2, |
| 3.1415925535897932e-3, |
| 3.1415925535897932e-4, |
| 3.1415925535897932e-5, |
| 3.1415925535897932e-6, |
| 3.1415925535897932e-7, |
| 3.1415925535897932e-8, |
| 3.1415925535897932e-9, |
| 3.1415925535897932e-10, |
| 3.1415925535897932e-11, |
| 3.1415925535897932e-12, |
| 3.1415925535897932e-13, |
| 3.1415925535897932e-14, |
| 3.1415925535897932e-15, |
| }; |
| |
| /* |
| * are the numbers close? |
| * used to compare long numbers where the last few digits are garbage |
| * due to precision problems |
| */ |
| static int |
| numclose(char *num1, char *num2) |
| { |
| int ndig; |
| double d1, d2; |
| enum { MAXDIG = 15 }; |
| |
| d1 = fmtstrtod(num1, 0); |
| d2 = fmtstrtod(num2, 0); |
| if(d1 != d2) |
| return 0; |
| |
| ndig = 0; |
| while (*num1) { |
| if (*num1 >= '0' && *num1 <= '9') { |
| ndig++; |
| if (ndig > MAXDIG) { |
| if (!(*num2 >= '0' && *num2 <= '9')) { |
| return 0; |
| } |
| } else if (*num1 != *num2) { |
| return 0; |
| } |
| } else if (*num1 != *num2) { |
| return 0; |
| } else if (*num1 == 'e' || *num1 == 'E') { |
| ndig = 0; |
| } |
| num1++; |
| num2++; |
| } |
| if (*num1 || !num2) |
| return 0; |
| return 1; |
| } |
| |
| static void |
| doit(int just, int plus, int alt, int zero, int width, int prec, int spec) |
| { |
| char format[256]; |
| char *p; |
| const char *s; |
| int i; |
| |
| p = format; |
| *p++ = '%'; |
| if (just > 0) |
| *p++ = "-"[just - 1]; |
| if (plus > 0) |
| *p++ = "+ "[plus - 1]; |
| if (alt > 0) |
| *p++ = "#"[alt - 1]; |
| if (zero > 0) |
| *p++ = "0"[zero - 1]; |
| |
| s = ""; |
| switch (width) { |
| case 1: s = "1"; break; |
| case 2: s = "5"; break; |
| case 3: s = "10"; break; |
| case 4: s = "15"; break; |
| } |
| strcpy(p, s); |
| |
| s = ""; |
| switch (prec) { |
| case 1: s = ".0"; break; |
| case 2: s = ".2"; break; |
| case 3: s = ".5"; break; |
| case 4: s = ".15"; break; |
| } |
| strcat(p, s); |
| |
| p = strchr(p, '\0'); |
| *p++ = "efgEG"[spec]; |
| *p = '\0'; |
| |
| for (i = 0; i < sizeof(fmtvals) / sizeof(fmtvals[0]); i++) { |
| char ref[1024], buf[1024]; |
| Rune rbuf[1024]; |
| double d1, d2; |
| |
| sprintf(ref, format, fmtvals[i]); |
| snprint(buf, sizeof(buf), format, fmtvals[i]); |
| if (strcmp(ref, buf) != 0 |
| && !numclose(ref, buf)) { |
| d1 = fmtstrtod(ref, 0); |
| d2 = fmtstrtod(buf, 0); |
| fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n", |
| format, |
| ref, d1==fmtvals[i] ? "" : " (ref is inexact!)", |
| buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)"); |
| // exits("oops"); |
| } |
| |
| /* Check again with output to rune string */ |
| runesnprint(rbuf, 1024, format, fmtvals[i]); |
| snprint(buf, sizeof(buf), "%S", rbuf); |
| if (strcmp(ref, buf) != 0 |
| && !numclose(ref, buf)) { |
| d1 = fmtstrtod(ref, 0); |
| d2 = fmtstrtod(buf, 0); |
| fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n", |
| format, |
| ref, d1==fmtvals[i] ? "" : " (ref is inexact!)", |
| buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)"); |
| // exits("oops"); |
| } |
| } |
| } |
| |
| void |
| main(int argc, char **argv) |
| { |
| int just, plus, alt, zero, width, prec, spec; |
| |
| for (just = 0; just < Njust; just++) |
| for (plus = 0; plus < Nplus; plus++) |
| for (alt = 0; alt < Nalt; alt++) |
| for (zero = 0; zero < Nzero; zero++) |
| for (width = 0; width < Nwidth; width++) |
| for (prec = 0; prec < Nprec; prec++) |
| for (spec = 0; spec < Nspec; spec++) |
| doit(just, plus, alt, zero, width, prec, spec); |
| |
| exits(0); |
| } |