2 * The purpose of this utility is to generate valid C arrays of exact
3 * (x, ..., func(x, ...)) pairs for consumption by the rest of the test cases.
5 * The code is a bit ugly. Sorry, tried to do it as less ugly as possible.
7 #define _XOPEN_SOURCE 600
22 #include "subr_random.h"
24 /* Function prototypes */
25 #define DECL_GEN(type) \
26 static void gen_##type(const char *fname, size_t total, \
27 type lower, type upper, type delta)
28 typedef long double long_double;
30 DECL_GEN(long_double);
31 static void usage(const char *progname);
32 static char *strtoupper(const char *str);
33 static long double mystrtold(const char *str, const char *what);
34 static void ifdef_guard_open(const char *fname);
35 static void ifdef_guard_close(const char *fname);
36 static void struct_decl_open(const char *fname, const char *type);
37 static void struct_decl_close(void);
40 * Bite the bullet and don't protect macro arguments with surrounding
41 * parentheses nor use intermediate variables. Trade safety, for pleasure.
43 #define COMPUTE_EXACT_VAL(f, mp_exact, mp_x, mp_y, rndmode) \
46 f->f_mpfr(mp_exact, mp_x, rndmode); \
48 f->f_mpfr(mp_exact, mp_x, mp_y, rndmode); \
52 * `d' represents the symmetric interval around zero that we exclude.
53 * We do so because floating-point numbers tend to become more dense
54 * around zero and less so towards the infinities. And we don't want
55 * to be massively spammed with tiny values (I've seen it happening).
57 * A little bit suboptimal for the f_narg = 2 case, as we may be
58 * discarding -say- valid x values, because y was out of bounds.
60 #define GET_RANDOM_VAL(type, f, x, y, d) \
62 if (f->f_narg == 1) { \
64 x = random_##type(FP_NORMAL); \
65 } while (x < lower || x > upper || fabs(x) < d || \
69 if (f->f_narg == 2) { \
71 x = random_##type(FP_NORMAL); \
72 y = random_##type(FP_NORMAL); \
73 } while (x < lower || x > upper || \
74 y < lower || y > upper || \
75 fabsl(x) < d || fabsl(y) < d || \
81 * Skip the inexact exception
83 * In case of a non-zero real rounded result, the error on the result is less
84 * or equal to 1/2 ulp (unit in the last place) of that result in the rounding
85 * to nearest mode, and less than 1 ulp of that result in the directed rounding
86 * modes. We use much more bits than double / long double anyway, so a 0.5 ulp
87 * or even 1 ulp doesn't make any difference.
89 #define MPFR_ERROR(x) \
90 (mpfr_underflow_p() || mpfr_overflow_p() || mpfr_nanflag_p() \
91 || mpfr_erangeflag_p())
93 /* Used for debugging purposes only */
94 #define MPFR_PRINT_FLAGS(x) \
96 if (mpfr_underflow_p()) \
97 fprintf(stderr, "Underflow\n"); \
98 if (mpfr_overflow_p()) \
99 fprintf(stderr, "Overflow\n"); \
100 if (mpfr_nanflag_p()) \
101 fprintf(stderr, "NaN\n"); \
102 if (mpfr_inexflag_p()) \
103 fprintf(stderr, "Inexact\n"); \
104 if (mpfr_erangeflag_p()) \
105 fprintf(stderr, "Erange\n"); \
106 fprintf(stderr, "\n"); \
109 #define MPFR_PRINT_FPCLASS(x) \
112 fprintf(stderr, "Nan\n"); \
114 fprintf(stderr, "Inf\n"); \
115 if (mpfr_number_p(x)) \
116 fprintf(stderr, "Number (neither NaN nor Inf)\n"); \
117 if (mpfr_zero_p(x)) \
118 fprintf(stderr, "Zero\n"); \
122 main(int argc, char *argv[])
124 const char *progname, *fname, *type;
125 long double min, max, delta;
126 long double ldlower, ldupper;
127 double dlower, dupper;
131 * Save program name, function name and floating-point type.
132 * We will be using them later.
139 /* Parse arguments */
141 while ((opt = getopt(argc, argv, "d:m:M:t:")) != -1) {
144 delta = mystrtold(optarg, "delta");
147 min = mystrtold(optarg, "min");
150 max = mystrtold(optarg, "Max");
153 total = atoi(optarg);
161 /* optind is the argv[] index of the first non-option element */
163 fprintf(stderr, "non-option argv[]-elements: ");
164 while (optind < argc)
165 fprintf(stderr, "%s ", argv[optind++]);
166 fprintf(stderr, "\n");
171 /* Validate input -- make sure all arguments were given */
172 if (total < 0 || min > max || argc != 7) {
177 if (strcmp(type, "float") && strcmp(type, "double")
178 && (strcmp(type, "ldouble") && strcmp(type, "all"))) {
183 /* Initialize random number generator */
186 /* Open #ifdef guard */
187 ifdef_guard_open(fname);
190 if (!strcmp(type, "double") || !strcmp(type, "all")) {
193 struct_decl_open(fname, "double");
194 gen_double(fname, total, dlower, dupper, delta);
198 if (!strcmp(type, "ldouble") || !strcmp(type, "all")) {
201 struct_decl_open(fname, "long double");
202 gen_long_double(fname, total, ldlower, ldupper, delta);
206 /* Close #ifdef guard */
207 ifdef_guard_close(fname);
209 return (EXIT_SUCCESS);
213 gen_double(const char *fname, size_t total,
214 double lower, double upper, double delta)
216 const struct fentry *f;
217 const mpfr_rnd_t tonearest = GMP_RNDN;
218 mpfr_t mp_x, mp_y, mp_exact;
222 /* Look up the function */
223 f = getfunctionbyname(fname);
226 /* Initialize high precision variables */
227 mpfr_inits2(97, mp_x, mp_y, mp_exact, (mpfr_ptr)NULL);
229 for (i = 0; i < total; i++) {
230 /* Generate a random input for function f */
231 GET_RANDOM_VAL(double, f, x, y, delta);
233 /* Set the mpfr variables */
235 mpfr_set_d(mp_x, x, tonearest);
237 mpfr_set_d(mp_y, y, tonearest);
238 mpfr_set_d(mp_exact, 0.0, tonearest);
240 /* Compute exact value, mp_exact = f(mp_x, ...) */
242 COMPUTE_EXACT_VAL(f, mp_exact, mp_x, mp_y, tonearest);
243 if (MPFR_ERROR() || !mpfr_number_p(mp_exact)) {
244 fprintf(stderr, "ERROR: exactf value overflowed\n");
249 /* mpfr_fprintf(stderr, "-> %.35RNg\n", mp_exact); */
251 /* Extract exact value */
252 exact = mpfr_get_d(mp_exact, tonearest);
253 if (fpclassify(exact) != FP_NORMAL) {
259 printf("\t{ % .16e, % .16e }", x, exact);
261 printf("\t{ % .16e,\n\t % .16e,\n\t % .16e }", x, y, exact);
270 mpfr_clears(mp_x, mp_y, mp_exact, (mpfr_ptr)NULL);
274 gen_long_double(const char *fname, size_t total,
275 long double lower, long double upper, long double delta)
277 const struct fentry *f;
278 const mpfr_rnd_t tonearest = GMP_RNDN;
279 mpfr_t mp_x, mp_y, mp_exact;
280 long double x, y, exact;
283 /* Lookup the function */
284 f = getfunctionbyname(fname);
287 /* Initialize high precision variables */
288 mpfr_inits2(97, mp_x, mp_y, mp_exact, (mpfr_ptr)NULL);
290 for (i = 0; i < total; i++) {
291 /* Generate a random input for function f */
292 GET_RANDOM_VAL(long_double, f, x, y, delta);
294 /* Set the mpfr variables */
296 mpfr_set_ld(mp_x, x, tonearest);
298 mpfr_set_ld(mp_y, y, tonearest);
299 mpfr_set_ld(mp_exact, 0.0, tonearest);
301 /* Compute exact value, mp_exact = f(mp_x, ...) */
303 COMPUTE_EXACT_VAL(f, mp_exact, mp_x, mp_y, tonearest);
304 if (MPFR_ERROR() || !mpfr_number_p(mp_exact)) {
309 /* mpfr_fprintf(stderr, "-> %.35RNg\n", mp_exact); */
311 /* Extract exact value */
312 exact = mpfr_get_ld(mp_exact, tonearest);
313 if (fpclassify(exact) != FP_NORMAL) {
314 fprintf(stderr, "ERROR: exactl value overflowed\n");
320 * Don't forget the L suffix in long double floating-point
321 * constants, as by default they are treated as double.
324 printf("\t{ % .35LeL, % .35LeL }", x, exact);
326 printf("\t{ % .35LeL, % .35LeL,\n\t% .35LeL }", x, y, exact);
335 mpfr_clears(mp_x, mp_y, mp_exact, (mpfr_ptr)NULL);
339 usage(const char *progname)
342 "usage: %s fname fptype -t total -m min -M Max -d delta\n"
343 "\t`fname' is the function name, as declared in math.h\n"
344 "\t`fptype' is one of `double', `ldouble' or `all'\n"
345 "\t`total' is the total number of (x, ..., f(x, ...)) pairs\n"
346 "\t`delta' is the interval around zero to exclude\n"
347 "\t`min' and `Max' are long double constants\n"
348 "\t(+-INF or INFINITY are acceptable input)\n"
350 "%s sin all -t10 -m-Inf -MInf -d1E-10\n",
357 * The caller must free up the memory
360 strtoupper(const char *str)
367 newstr = malloc(strlen(str)+1);
373 *newp = toupper(*oldp);
381 mystrtold(const char *str, const char *what)
388 rv = strtold(str, &endp);
392 "WARNING: Conversion stopped at %s (was given = %s)\n"
393 "WARNING: Continuing with %s = %.35Le\n",
394 endp, str, what, rv);
396 /* We only allow over/under-flows to happen (ERANGE) */
407 ifdef_guard_open(const char *fname)
411 FNAME = strtoupper(fname);
412 printf("#ifndef __T_%s_H__\n", FNAME);
413 printf("#define __T_%s_H__\n", FNAME);
420 ifdef_guard_close(const char *fname)
424 FNAME = strtoupper(fname);
425 printf("#endif /* ! __T_%s_H__ */\n", FNAME);
431 struct_decl_open(const char *fname, const char *type)
433 const struct fentry *f;
436 f = getfunctionbyname(fname);
439 str = strcmp(type, "double") == 0 ? "" : "l";
441 if (f->f_narg == 1) {
442 printf("const struct\nt1%sdentry {\n"
443 "\t%s x; /* Input */\n"
444 "\t%s y; /* Output */\n"
445 "} t1%sdtable[] = {\n",
446 str, type, type, str);
448 printf("const struct\nt1%sdentry {\n"
449 "\t%s x; /* Input */\n"
450 "\t%s y; /* Input */\n"
451 "\t%s z; /* Output */\n"
452 "} t1%sdtable[] = {\n",
453 str, type, type, type, str);
458 struct_decl_close(void)