1 /* Read data file and check function.
3 Copyright (C) 2008, 2009, 2010 Andreas Enge, Philippe Th\'eveny
5 This file is part of the MPC Library.
7 The MPC Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or (at your
10 option) any later version.
12 The MPC Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with the MPC Library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 MA 02111-1307, USA. */
24 #include "mpc-tests.h"
27 unsigned long line_number;
28 /* file name with complete path and currently read line;
29 kept globally to simplify parameter passing */
30 unsigned long test_line_number;
31 /* start line of data test (which may extend over several lines) */
33 /* character appearing next in the file, may be EOF */
35 #define MPC_INEX_CMP(r, i, c) \
36 (((r) == TERNARY_NOT_CHECKED || (r) == MPC_INEX_RE(c)) \
37 && ((i) == TERNARY_NOT_CHECKED || (i) == MPC_INEX_IM (c)))
39 #define MPFR_INEX_STR(inex) \
40 (inex) == TERNARY_NOT_CHECKED ? "?" \
41 : (inex) == +1 ? "+1" \
42 : (inex) == -1 ? "-1" : "0"
44 static const char *mpfr_rnd_mode [] =
45 { "GMP_RNDN", "GMP_RNDZ", "GMP_RNDU", "GMP_RNDD" };
47 const char *rnd_mode[] =
48 { "MPC_RNDNN", "MPC_RNDZN", "MPC_RNDUN", "MPC_RNDDN",
49 "undefined", "undefined", "undefined", "undefined", "undefined",
50 "undefined", "undefined", "undefined", "undefined", "undefined",
51 "undefined", "undefined",
52 "MPC_RNDNZ", "MPC_RNDZZ", "MPC_RNDUZ", "MPC_RNDDZ",
53 "undefined", "undefined", "undefined", "undefined", "undefined",
54 "undefined", "undefined", "undefined", "undefined", "undefined",
55 "undefined", "undefined",
56 "MPC_RNDNU", "MPC_RNDZU", "MPC_RNDUU", "MPC_RNDDU",
57 "undefined", "undefined", "undefined", "undefined", "undefined",
58 "undefined", "undefined", "undefined", "undefined", "undefined",
59 "undefined", "undefined",
60 "MPC_RNDND", "MPC_RNDZD", "MPC_RNDUD", "MPC_RNDDD",
61 "undefined", "undefined", "undefined", "undefined", "undefined",
62 "undefined", "undefined", "undefined", "undefined", "undefined",
63 "undefined", "undefined",
68 open_data_file (const char *file_name)
72 char default_srcdir[] = ".";
74 src_dir = getenv ("srcdir");
76 src_dir = default_srcdir;
78 pathname = (char *) malloc ((strlen (src_dir)) + strlen (file_name) + 2);
81 printf ("Cannot allocate memory\n");
84 sprintf (pathname, "%s/%s", src_dir, file_name);
85 fp = fopen (pathname, "r");
88 fprintf (stderr, "Unable to open %s\n", pathname);
96 close_data_file (FILE *fp)
102 /* read primitives */
105 /* skips characters until reaching '\n' or EOF; */
106 /* '\n' is skipped as well */
108 while (nextchar != EOF && nextchar != '\n')
109 nextchar = getc (fp);
113 nextchar = getc (fp);
118 skip_whitespace (FILE *fp)
119 /* skips over whitespace if any until reaching EOF */
120 /* or non-whitespace */
122 while (isspace (nextchar))
124 if (nextchar == '\n')
126 nextchar = getc (fp);
131 skip_whitespace_comments (FILE *fp)
132 /* skips over all whitespace and comments, if any */
134 skip_whitespace (fp);
135 while (nextchar == '#') {
138 skip_whitespace (fp);
144 read_string (FILE *fp, char **buffer_ptr, size_t buffer_length, const char *name)
150 buffer = *buffer_ptr;
153 nextchar = getc (fp);
157 while (nextchar != EOF && nextchar != '"')
159 if (nextchar == '\n')
161 if (pos + 1 > buffer_length)
163 buffer = (char *) realloc (buffer, 2 * buffer_length);
166 printf ("Cannot allocate memory\n");
171 buffer[pos++] = nextchar;
172 nextchar = getc (fp);
178 if (pos + 1 > buffer_length)
180 buffer = (char *) realloc (buffer, buffer_length + 1);
183 printf ("Cannot allocate memory\n");
190 nextchar = getc (fp);
191 skip_whitespace_comments (fp);
193 buffer_ptr = &buffer;
195 return buffer_length;
198 printf ("Error: Unable to read %s in file '%s' line '%lu'\n",
199 name, pathname, line_number);
203 /* All following read routines skip over whitespace and comments; */
204 /* so after calling them, nextchar is either EOF or the beginning */
205 /* of a non-comment token. */
207 read_ternary (FILE *fp, int* ternary)
212 *ternary = TERNARY_ERROR;
215 *ternary = TERNARY_NOT_CHECKED;
227 printf ("Error: Unexpected ternary value '%c' in file '%s' line %lu\n",
228 nextchar, pathname, line_number);
232 nextchar = getc (fp);
233 skip_whitespace_comments (fp);
237 read_mpfr_rounding_mode (FILE *fp, mpfr_rnd_t* rnd)
254 printf ("Error: Unexpected rounding mode '%c' in file '%s' line %lu\n",
255 nextchar, pathname, line_number);
259 nextchar = getc (fp);
260 if (nextchar != EOF && !isspace (nextchar)) {
261 printf ("Error: Rounding mode not followed by white space in file "
263 pathname, line_number);
266 skip_whitespace_comments (fp);
270 read_mpc_rounding_mode (FILE *fp, mpc_rnd_t* rnd)
273 read_mpfr_rounding_mode (fp, &re);
274 read_mpfr_rounding_mode (fp, &im);
275 *rnd = RNDC (re, im);
279 read_int (FILE *fp, int *nread, const char *name)
285 printf ("Error: Unexpected EOF when reading int "
286 "in file '%s' line %lu\n",
287 pathname, line_number);
290 ungetc (nextchar, fp);
291 n = fscanf (fp, "%i", nread);
292 if (ferror (fp) || n == 0 || n == EOF)
294 printf ("Error: Cannot read %s in file '%s' line %lu\n",
295 name, pathname, line_number);
298 nextchar = getc (fp);
299 skip_whitespace_comments (fp);
303 read_uint (FILE *fp, unsigned long int *ui)
309 printf ("Error: Unexpected EOF when reading uint "
310 "in file '%s' line %lu\n",
311 pathname, line_number);
314 ungetc (nextchar, fp);
315 n = fscanf (fp, "%lu", ui);
316 if (ferror (fp) || n == 0 || n == EOF)
318 printf ("Error: Cannot read uint in file '%s' line %lu\n",
319 pathname, line_number);
322 nextchar = getc (fp);
323 skip_whitespace_comments (fp);
327 read_mpfr_prec (FILE *fp)
332 if (nextchar == EOF) {
333 printf ("Error: Unexpected EOF when reading mpfr precision "
334 "in file '%s' line %lu\n",
335 pathname, line_number);
338 ungetc (nextchar, fp);
339 n = fscanf (fp, "%lu", &prec);
340 if (ferror (fp)) /* then also n == EOF */
341 perror ("Error when reading mpfr precision");
342 if (n == 0 || n == EOF || prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
343 printf ("Error: Impossible mpfr precision in file '%s' line %lu\n",
344 pathname, line_number);
347 nextchar = getc (fp);
348 skip_whitespace_comments (fp);
349 return (mpfr_prec_t) prec;
353 read_mpfr_mantissa (FILE *fp, mpfr_ptr x)
355 if (nextchar == EOF) {
356 printf ("Error: Unexpected EOF when reading mpfr mantissa "
357 "in file '%s' line %lu\n",
358 pathname, line_number);
361 ungetc (nextchar, fp);
362 if (mpfr_inp_str (x, fp, 0, GMP_RNDN) == 0) {
363 printf ("Error: Impossible to read mpfr mantissa "
364 "in file '%s' line %lu\n",
365 pathname, line_number);
368 nextchar = getc (fp);
369 skip_whitespace_comments (fp);
373 read_mpfr (FILE *fp, mpfr_ptr x, int *known_sign)
376 mpfr_set_prec (x, read_mpfr_prec (fp));
378 read_mpfr_mantissa (fp, x);
380 /* the sign always matters for regular values ('+' is implicit),
381 but when no sign appears before 0 or Inf in the data file, it means
382 that only absolute value must be checked. */
383 if (known_sign != NULL)
385 (!mpfr_zero_p (x) && !mpfr_inf_p (x))
386 || sign == '+' || sign == '-';
390 read_mpc (FILE *fp, mpc_ptr z, known_signs_t *ks)
392 read_mpfr (fp, MPC_RE (z), ks == NULL ? NULL : &ks->re);
393 read_mpfr (fp, MPC_IM (z), ks == NULL ? NULL : &ks->im);
397 check_compatible (int inex, mpfr_t expected, mpfr_rnd_t rnd, char *s)
399 if ((rnd == GMP_RNDU && inex == -1) ||
400 (rnd == GMP_RNDD && inex == +1) ||
401 (rnd == GMP_RNDZ && mpfr_signbit (expected) == 0 && inex == +1) ||
402 (rnd == GMP_RNDZ && mpfr_signbit (expected) == 1 && inex == -1))
405 printf ("Incompatible ternary value '%c' (%s part) in file '%s' line %lu\n",
406 (inex == 1) ? '+' : '-', s, pathname, test_line_number);
408 printf ("Incompatible ternary value '%c' in file '%s' line %lu\n",
409 (inex == 1) ? '+' : '-', pathname, test_line_number);
413 /* read lines of data */
415 read_cc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
416 known_signs_t *signs, mpc_ptr op, mpc_rnd_t *rnd)
418 test_line_number = line_number;
419 read_ternary (fp, inex_re);
420 read_ternary (fp, inex_im);
421 read_mpc (fp, expected, signs);
422 read_mpc (fp, op, NULL);
423 read_mpc_rounding_mode (fp, rnd);
424 check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
425 check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
429 read_fc (FILE *fp, int *inex, mpfr_ptr expected, int *sign, mpc_ptr op,
432 test_line_number = line_number;
433 read_ternary (fp, inex);
434 read_mpfr (fp, expected, sign);
435 read_mpc (fp, op, NULL);
436 read_mpfr_rounding_mode (fp, rnd);
437 check_compatible (*inex, expected, *rnd, NULL);
441 read_ccc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
442 known_signs_t *signs, mpc_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
444 test_line_number = line_number;
445 read_ternary (fp, inex_re);
446 read_ternary (fp, inex_im);
447 read_mpc (fp, expected, signs);
448 read_mpc (fp, op1, NULL);
449 read_mpc (fp, op2, NULL);
450 read_mpc_rounding_mode (fp, rnd);
451 check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
452 check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
456 read_cfc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
457 known_signs_t *signs, mpfr_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
459 test_line_number = line_number;
460 read_ternary (fp, inex_re);
461 read_ternary (fp, inex_im);
462 read_mpc (fp, expected, signs);
463 read_mpfr (fp, op1, NULL);
464 read_mpc (fp, op2, NULL);
465 read_mpc_rounding_mode (fp, rnd);
466 check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
467 check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
471 read_ccf (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
472 known_signs_t *signs, mpc_ptr op1, mpfr_ptr op2, mpc_rnd_t *rnd)
474 test_line_number = line_number;
475 read_ternary (fp, inex_re);
476 read_ternary (fp, inex_im);
477 read_mpc (fp, expected, signs);
478 read_mpc (fp, op1, NULL);
479 read_mpfr (fp, op2, NULL);
480 read_mpc_rounding_mode (fp, rnd);
481 check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
482 check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
486 read_ccu (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
487 known_signs_t *signs, mpc_ptr op1, unsigned long int *op2, mpc_rnd_t *rnd)
489 test_line_number = line_number;
490 read_ternary (fp, inex_re);
491 read_ternary (fp, inex_im);
492 read_mpc (fp, expected, signs);
493 read_mpc (fp, op1, NULL);
495 read_mpc_rounding_mode (fp, rnd);
496 check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
497 check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
500 /* data_check (function, data_file_name) checks function results against
501 precomputed data in a file.*/
503 data_check (mpc_function function, const char *file_name)
509 mpfr_rnd_t mpfr_rnd = GMP_RNDN;
513 mpc_t z1, z2, z3, z4;
514 mpc_rnd_t rnd = MPC_RNDNN;
516 unsigned long int ui;
521 fp = open_data_file (file_name);
523 /* 1. init needed variables */
525 switch (function.type)
549 /* 2. read data file */
551 nextchar = getc (fp);
552 skip_whitespace_comments (fp);
553 while (nextchar != EOF) {
554 /* for each kind of function prototype: */
555 /* 3.1 read a line of data: expected result, parameters, rounding mode */
556 /* 3.2 compute function at the same precision as the expected result */
557 /* 3.3 compare this result with the expected one */
558 switch (function.type)
560 case FC: /* example mpc_norm */
561 read_fc (fp, &inex_re, x1, &sign_real, z1, &mpfr_rnd);
562 mpfr_set_prec (x2, MPFR_PREC (x1));
563 inex = function.pointer.FC (x2, z1, mpfr_rnd);
564 if ((inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
565 || !same_mpfr_value (x1, x2, sign_real))
567 mpfr_t got, expected;
572 printf ("%s(op) failed (%s:%lu)\nwith rounding mode %s\n",
573 function.name, file_name, test_line_number,
574 mpfr_rnd_mode[mpfr_rnd]);
575 if (inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
576 printf("ternary value: got %s, expected %s\n",
577 MPFR_INEX_STR (inex), MPFR_INEX_STR (inex_re));
587 case CC: /* example mpc_log */
588 read_cc (fp, &inex_re, &inex_im, z1, &signs, z2, &rnd);
589 mpfr_set_prec (MPC_RE (z3), MPC_PREC_RE (z1));
590 mpfr_set_prec (MPC_IM (z3), MPC_PREC_IM (z1));
591 inex = function.pointer.CC (z3, z2, rnd);
592 if (!MPC_INEX_CMP (inex_re, inex_im, inex)
593 || !same_mpc_value (z3, z1, signs))
595 mpc_t op, got, expected; /* display sensible variable names */
599 printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
600 function.name, test_line_number, rnd_mode[rnd]);
601 if (!MPC_INEX_CMP (inex_re, inex_im, inex))
602 printf("ternary value: got %s, expected (%s, %s)\n",
604 MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
614 case CCC: /* example mpc_mul */
615 read_ccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, &rnd);
616 mpfr_set_prec (MPC_RE(z4), MPC_PREC_RE (z1));
617 mpfr_set_prec (MPC_IM(z4), MPC_PREC_IM (z1));
618 inex = function.pointer.CCC (z4, z2, z3, rnd);
619 if (!MPC_INEX_CMP (inex_re, inex_im, inex)
620 || !same_mpc_value (z4, z1, signs))
622 /* display sensible variable names */
623 mpc_t op1, op2, got, expected;
628 printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
629 function.name, test_line_number, rnd_mode[rnd]);
630 if (!MPC_INEX_CMP (inex_re, inex_im, inex))
631 printf("ternary value: got %s, expected (%s, %s)\n",
633 MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
642 if (function.properties & FUNC_PROP_SYMETRIC)
644 inex = function.pointer.CCC (z4, z3, z2, rnd);
645 if (!MPC_INEX_CMP (inex_re, inex_im, inex)
646 || !same_mpc_value (z4, z1, signs))
648 /* display sensible variable names */
649 mpc_t op1, op2, got, expected;
654 printf ("%s(op) failed (line %lu/symetric test)\n"
655 "with rounding mode %s\n",
656 function.name, test_line_number, rnd_mode[rnd]);
657 if (!MPC_INEX_CMP (inex_re, inex_im, inex))
658 printf("ternary value: got %s, expected (%s, %s)\n",
660 MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
672 case CFC: /* example mpc_fr_div */
673 read_cfc (fp, &inex_re, &inex_im, z1, &signs, x1, z2, &rnd);
674 mpfr_set_prec (MPC_RE(z3), MPC_PREC_RE (z1));
675 mpfr_set_prec (MPC_IM(z3), MPC_PREC_IM (z1));
676 inex = function.pointer.CFC (z3, x1, z2, rnd);
677 if (!MPC_INEX_CMP (inex_re, inex_im, inex)
678 || !same_mpc_value (z3, z1, signs))
680 /* display sensible variable names */
681 mpc_t op2, got, expected;
687 printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
688 function.name, test_line_number, rnd_mode[rnd]);
689 if (!MPC_INEX_CMP (inex_re, inex_im, inex))
690 printf("ternary value: got %s, expected (%s, %s)\n",
692 MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
703 case CCF: /* example mpc_mul_fr */
704 read_ccf (fp, &inex_re, &inex_im, z1, &signs, z2, x1, &rnd);
705 mpfr_set_prec (MPC_RE(z3), MPC_PREC_RE (z1));
706 mpfr_set_prec (MPC_IM(z3), MPC_PREC_IM (z1));
707 inex = function.pointer.CCF (z3, z2, x1, rnd);
708 if (!MPC_INEX_CMP (inex_re, inex_im, inex)
709 || !same_mpc_value (z3, z1, signs))
711 /* display sensible variable names */
712 mpc_t op1, got, expected;
718 printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
719 function.name, test_line_number, rnd_mode[rnd]);
720 if (!MPC_INEX_CMP (inex_re, inex_im, inex))
721 printf("ternary value: got %s, expected (%s, %s)\n",
723 MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
734 case CCU: /* example mpc_pow_ui */
735 read_ccu (fp, &inex_re, &inex_im, z1, &signs, z2, &ui, &rnd);
736 mpfr_set_prec (MPC_RE(z3), MPC_PREC_RE (z1));
737 mpfr_set_prec (MPC_IM(z3), MPC_PREC_IM (z1));
738 inex = function.pointer.CCU (z3, z2, ui, rnd);
739 if (!MPC_INEX_CMP (inex_re, inex_im, inex)
740 || !same_mpc_value (z3, z1, signs))
742 /* display sensible variable names */
743 mpc_t op1, got, expected;
747 printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
748 function.name, test_line_number, rnd_mode[rnd]);
749 if (!MPC_INEX_CMP (inex_re, inex_im, inex))
750 printf("ternary value: got %s, expected (%s, %s)\n",
752 MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
754 printf ("op2 %lu\n ", ui);
767 /* 3. Clear used variables */
769 switch (function.type)
793 close_data_file (fp);