1/* read_data,c -- Read data file and check function.
2
3Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
4
5This file is part of GNU MPC.
6
7GNU MPC is free software; you can redistribute it and/or modify it under
8the terms of the GNU Lesser General Public License as published by the
9Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with this program. If not, see http://www.gnu.org/licenses/ .
19*/
20
21#include <stdlib.h>
22#include <string.h>
23#include "mpc-tests.h"
24
25char *pathname;
26unsigned long line_number;
27   /* file name with complete path and currently read line;
28      kept globally to simplify parameter passing */
29unsigned long test_line_number;
30   /* start line of data test (which may extend over several lines) */
31int nextchar;
32   /* character appearing next in the file, may be EOF */
33
34#define MPC_INEX_CMP(r, i, c)                                 \
35  (((r) == TERNARY_NOT_CHECKED || (r) == MPC_INEX_RE(c))      \
36   && ((i) == TERNARY_NOT_CHECKED || (i) == MPC_INEX_IM (c)))
37
38#define MPFR_INEX_STR(inex)                     \
39  (inex) == TERNARY_NOT_CHECKED ? "?"           \
40    : (inex) == +1 ? "+1"                       \
41    : (inex) == -1 ? "-1" : "0"
42
43static const char *mpfr_rnd_mode [] =
44  { "GMP_RNDN", "GMP_RNDZ", "GMP_RNDU", "GMP_RNDD" };
45
46const char *rnd_mode[] =
47  { "MPC_RNDNN", "MPC_RNDZN", "MPC_RNDUN", "MPC_RNDDN",
48    "undefined", "undefined", "undefined", "undefined", "undefined",
49    "undefined", "undefined", "undefined", "undefined", "undefined",
50    "undefined", "undefined",
51    "MPC_RNDNZ", "MPC_RNDZZ", "MPC_RNDUZ", "MPC_RNDDZ",
52    "undefined", "undefined", "undefined", "undefined", "undefined",
53    "undefined", "undefined", "undefined", "undefined", "undefined",
54    "undefined", "undefined",
55    "MPC_RNDNU", "MPC_RNDZU", "MPC_RNDUU", "MPC_RNDDU",
56    "undefined", "undefined", "undefined", "undefined", "undefined",
57    "undefined", "undefined", "undefined", "undefined", "undefined",
58    "undefined", "undefined",
59    "MPC_RNDND", "MPC_RNDZD", "MPC_RNDUD", "MPC_RNDDD",
60    "undefined", "undefined", "undefined", "undefined", "undefined",
61    "undefined", "undefined", "undefined", "undefined", "undefined",
62    "undefined", "undefined",
63  };
64
65/* file functions */
66FILE *
67open_data_file (const char *file_name)
68{
69  FILE *fp;
70  char *src_dir;
71  char default_srcdir[] = ".";
72
73  src_dir = getenv ("srcdir");
74  if (src_dir == NULL)
75    src_dir = default_srcdir;
76
77  pathname = (char *) malloc ((strlen (src_dir)) + strlen (file_name) + 2);
78  if (pathname == NULL)
79    {
80      printf ("Cannot allocate memory\n");
81      exit (1);
82    }
83  sprintf (pathname, "%s/%s", src_dir, file_name);
84  fp = fopen (pathname, "r");
85  if (fp == NULL)
86    {
87      fprintf (stderr, "Unable to open %s\n", pathname);
88      exit (1);
89    }
90
91  return fp;
92}
93
94void
95close_data_file (FILE *fp)
96{
97  free (pathname);
98  fclose (fp);
99}
100
101/* read primitives */
102static void
103skip_line (FILE *fp)
104   /* skips characters until reaching '\n' or EOF; */
105   /* '\n' is skipped as well                      */
106{
107   while (nextchar != EOF && nextchar != '\n')
108     nextchar = getc (fp);
109   if (nextchar != EOF)
110     {
111       line_number ++;
112       nextchar = getc (fp);
113     }
114}
115
116static void
117skip_whitespace (FILE *fp)
118   /* skips over whitespace if any until reaching EOF */
119   /* or non-whitespace                               */
120{
121   while (isspace (nextchar))
122     {
123       if (nextchar == '\n')
124         line_number ++;
125       nextchar = getc (fp);
126     }
127}
128
129void
130skip_whitespace_comments (FILE *fp)
131   /* skips over all whitespace and comments, if any */
132{
133   skip_whitespace (fp);
134   while (nextchar == '#') {
135      skip_line (fp);
136      if (nextchar != EOF)
137         skip_whitespace (fp);
138   }
139}
140
141
142size_t
143read_string (FILE *fp, char **buffer_ptr, size_t buffer_length, const char *name)
144{
145  size_t pos;
146  char *buffer;
147
148  pos = 0;
149  buffer = *buffer_ptr;
150
151  if (nextchar == '"')
152    nextchar = getc (fp);
153  else
154    goto error;
155
156  while (nextchar != EOF && nextchar != '"')
157    {
158      if (nextchar == '\n')
159        line_number ++;
160      if (pos + 1 > buffer_length)
161        {
162          buffer = (char *) realloc (buffer, 2 * buffer_length);
163          if (buffer == NULL)
164            {
165              printf ("Cannot allocate memory\n");
166              exit (1);
167            }
168          buffer_length *= 2;
169        }
170      buffer[pos++] = (char) nextchar;
171      nextchar = getc (fp);
172    }
173
174  if (nextchar != '"')
175    goto error;
176
177  if (pos + 1 > buffer_length)
178    {
179      buffer = (char *) realloc (buffer, buffer_length + 1);
180      if (buffer == NULL)
181        {
182          printf ("Cannot allocate memory\n");
183          exit (1);
184        }
185      buffer_length *= 2;
186    }
187  buffer[pos] = '\0';
188
189  nextchar = getc (fp);
190  skip_whitespace_comments (fp);
191
192  *buffer_ptr = buffer;
193
194  return buffer_length;
195
196 error:
197  printf ("Error: Unable to read %s in file '%s' line '%lu'\n",
198          name, pathname, line_number);
199  exit (1);
200}
201
202/* All following read routines skip over whitespace and comments; */
203/* so after calling them, nextchar is either EOF or the beginning */
204/* of a non-comment token.                                        */
205void
206read_ternary (FILE *fp, int* ternary)
207{
208  switch (nextchar)
209    {
210    case '!':
211      *ternary = TERNARY_ERROR;
212      break;
213    case '?':
214      *ternary = TERNARY_NOT_CHECKED;
215      break;
216    case '+':
217      *ternary = +1;
218      break;
219    case '0':
220      *ternary = 0;
221      break;
222    case '-':
223      *ternary = -1;
224      break;
225    default:
226      printf ("Error: Unexpected ternary value '%c' in file '%s' line %lu\n",
227              nextchar, pathname, line_number);
228      exit (1);
229    }
230
231  nextchar = getc (fp);
232  skip_whitespace_comments (fp);
233}
234
235void
236read_mpfr_rounding_mode (FILE *fp, mpfr_rnd_t* rnd)
237{
238  switch (nextchar)
239    {
240    case 'n': case 'N':
241      *rnd = GMP_RNDN;
242      break;
243    case 'z': case 'Z':
244      *rnd = GMP_RNDZ;
245      break;
246    case 'u': case 'U':
247      *rnd = GMP_RNDU;
248      break;
249    case 'd': case 'D':
250      *rnd = GMP_RNDD;
251      break;
252    default:
253      printf ("Error: Unexpected rounding mode '%c' in file '%s' line %lu\n",
254              nextchar, pathname, line_number);
255      exit (1);
256    }
257
258    nextchar = getc (fp);
259    if (nextchar != EOF && !isspace (nextchar)) {
260      printf ("Error: Rounding mode not followed by white space in file "
261              "'%s' line %lu\n",
262              pathname, line_number);
263      exit (1);
264    }
265    skip_whitespace_comments (fp);
266}
267
268void
269read_mpc_rounding_mode (FILE *fp, mpc_rnd_t* rnd)
270{
271   mpfr_rnd_t re, im;
272   read_mpfr_rounding_mode (fp, &re);
273   read_mpfr_rounding_mode (fp, &im);
274   *rnd = MPC_RND (re, im);
275}
276
277void
278read_int (FILE *fp, int *nread, const char *name)
279{
280  int n = 0;
281
282  if (nextchar == EOF)
283    {
284      printf ("Error: Unexpected EOF when reading int "
285              "in file '%s' line %lu\n",
286              pathname, line_number);
287      exit (1);
288    }
289  ungetc (nextchar, fp);
290  n = fscanf (fp, "%i", nread);
291  if (ferror (fp) || n == 0 || n == EOF)
292    {
293      printf ("Error: Cannot read %s in file '%s' line %lu\n",
294              name, pathname, line_number);
295      exit (1);
296    }
297  nextchar = getc (fp);
298  skip_whitespace_comments (fp);
299}
300
301static void
302read_uint (FILE *fp, unsigned long int *ui)
303{
304  int n = 0;
305
306  if (nextchar == EOF)
307    {
308      printf ("Error: Unexpected EOF when reading uint "
309              "in file '%s' line %lu\n",
310              pathname, line_number);
311      exit (1);
312    }
313  ungetc (nextchar, fp);
314  n = fscanf (fp, "%lu", ui);
315  if (ferror (fp) || n == 0 || n == EOF)
316    {
317      printf ("Error: Cannot read uint in file '%s' line %lu\n",
318              pathname, line_number);
319      exit (1);
320    }
321  nextchar = getc (fp);
322  skip_whitespace_comments (fp);
323}
324
325static void
326read_sint (FILE *fp, long int *si)
327{
328  int n = 0;
329
330  if (nextchar == EOF)
331    {
332      printf ("Error: Unexpected EOF when reading sint "
333              "in file '%s' line %lu\n",
334              pathname, line_number);
335      exit (1);
336    }
337  ungetc (nextchar, fp);
338  n = fscanf (fp, "%li", si);
339  if (ferror (fp) || n == 0 || n == EOF)
340    {
341      printf ("Error: Cannot read sint in file '%s' line %lu\n",
342              pathname, line_number);
343      exit (1);
344    }
345  nextchar = getc (fp);
346  skip_whitespace_comments (fp);
347}
348
349mpfr_prec_t
350read_mpfr_prec (FILE *fp)
351{
352   unsigned long prec;
353   int n;
354
355   if (nextchar == EOF) {
356      printf ("Error: Unexpected EOF when reading mpfr precision "
357              "in file '%s' line %lu\n",
358              pathname, line_number);
359      exit (1);
360   }
361   ungetc (nextchar, fp);
362   n = fscanf (fp, "%lu", &prec);
363   if (ferror (fp)) /* then also n == EOF */
364      perror ("Error when reading mpfr precision");
365   if (n == 0 || n == EOF || prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
366      printf ("Error: Impossible mpfr precision in file '%s' line %lu\n",
367              pathname, line_number);
368      exit (1);
369   }
370   nextchar = getc (fp);
371   skip_whitespace_comments (fp);
372   return (mpfr_prec_t) prec;
373}
374
375static void
376read_mpfr_mantissa (FILE *fp, mpfr_ptr x)
377{
378   if (nextchar == EOF) {
379      printf ("Error: Unexpected EOF when reading mpfr mantissa "
380              "in file '%s' line %lu\n",
381              pathname, line_number);
382      exit (1);
383   }
384   ungetc (nextchar, fp);
385   if (mpfr_inp_str (x, fp, 0, GMP_RNDN) == 0) {
386      printf ("Error: Impossible to read mpfr mantissa "
387              "in file '%s' line %lu\n",
388              pathname, line_number);
389      exit (1);
390   }
391   nextchar = getc (fp);
392   skip_whitespace_comments (fp);
393}
394
395void
396read_mpfr (FILE *fp, mpfr_ptr x, int *known_sign)
397{
398   int sign;
399   mpfr_set_prec (x, read_mpfr_prec (fp));
400   sign = nextchar;
401   read_mpfr_mantissa (fp, x);
402
403   /* the sign always matters for regular values ('+' is implicit),
404      but when no sign appears before 0 or Inf in the data file, it means
405      that only absolute value must be checked. */
406   if (known_sign != NULL)
407     *known_sign =
408       (!mpfr_zero_p (x) && !mpfr_inf_p (x))
409       || sign == '+' || sign == '-';
410}
411
412void
413read_mpc (FILE *fp, mpc_ptr z, known_signs_t *ks)
414{
415  read_mpfr (fp, mpc_realref (z), ks == NULL ? NULL : &ks->re);
416  read_mpfr (fp, mpc_imagref (z), ks == NULL ? NULL : &ks->im);
417}
418
419static void
420check_compatible (int inex, mpfr_t expected, mpfr_rnd_t rnd, const char *s)
421{
422  if ((rnd == GMP_RNDU && inex == -1) ||
423      (rnd == GMP_RNDD && inex == +1) ||
424      (rnd == GMP_RNDZ && !mpfr_signbit (expected) && inex == +1) ||
425      (rnd == GMP_RNDZ && mpfr_signbit (expected) && inex == -1))
426    {
427      if (s != NULL)
428        printf ("Incompatible ternary value '%c' (%s part) in file '%s' line %lu\n",
429              (inex == 1) ? '+' : '-', s, pathname, test_line_number);
430      else
431        printf ("Incompatible ternary value '%c' in file '%s' line %lu\n",
432              (inex == 1) ? '+' : '-', pathname, test_line_number);
433    }
434}
435
436/* read lines of data */
437static void
438read_cc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
439         known_signs_t *signs, mpc_ptr op, mpc_rnd_t *rnd)
440{
441  test_line_number = line_number;
442  read_ternary (fp, inex_re);
443  read_ternary (fp, inex_im);
444  read_mpc (fp, expected, signs);
445  read_mpc (fp, op, NULL);
446  read_mpc_rounding_mode (fp, rnd);
447  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
448  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
449}
450
451static void
452read_fc (FILE *fp, int *inex, mpfr_ptr expected, int *sign, mpc_ptr op,
453         mpfr_rnd_t *rnd)
454{
455  test_line_number = line_number;
456  read_ternary (fp, inex);
457  read_mpfr (fp, expected, sign);
458  read_mpc (fp, op, NULL);
459  read_mpfr_rounding_mode (fp, rnd);
460  check_compatible (*inex, expected, *rnd, NULL);
461}
462
463static void
464read_ccc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
465          known_signs_t *signs, mpc_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
466{
467  test_line_number = line_number;
468  read_ternary (fp, inex_re);
469  read_ternary (fp, inex_im);
470  read_mpc (fp, expected, signs);
471  read_mpc (fp, op1, NULL);
472  read_mpc (fp, op2, NULL);
473  read_mpc_rounding_mode (fp, rnd);
474  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
475  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
476}
477
478/* read lines of data for function with three mpc_t inputs and one mpc_t
479   output like mpc_fma */
480static void
481read_cccc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
482	   known_signs_t *signs, mpc_ptr op1, mpc_ptr op2, mpc_ptr op3,
483	   mpc_rnd_t *rnd)
484{
485  test_line_number = line_number;
486  read_ternary (fp, inex_re);
487  read_ternary (fp, inex_im);
488  read_mpc (fp, expected, signs);
489  read_mpc (fp, op1, NULL);
490  read_mpc (fp, op2, NULL);
491  read_mpc (fp, op3, NULL);
492  read_mpc_rounding_mode (fp, rnd);
493  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
494  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
495}
496
497static void
498read_cfc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
499          known_signs_t *signs, mpfr_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
500{
501  test_line_number = line_number;
502  read_ternary (fp, inex_re);
503  read_ternary (fp, inex_im);
504  read_mpc (fp, expected, signs);
505  read_mpfr (fp, op1, NULL);
506  read_mpc (fp, op2, NULL);
507  read_mpc_rounding_mode (fp, rnd);
508  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
509  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
510}
511
512static void
513read_ccf (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
514          known_signs_t *signs, mpc_ptr op1, mpfr_ptr op2, mpc_rnd_t *rnd)
515{
516  test_line_number = line_number;
517  read_ternary (fp, inex_re);
518  read_ternary (fp, inex_im);
519  read_mpc (fp, expected, signs);
520  read_mpc (fp, op1, NULL);
521  read_mpfr (fp, op2, NULL);
522  read_mpc_rounding_mode (fp, rnd);
523  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
524  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
525}
526
527static void
528read_ccu (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
529          known_signs_t *signs, mpc_ptr op1, unsigned long int *op2, mpc_rnd_t *rnd)
530{
531  test_line_number = line_number;
532  read_ternary (fp, inex_re);
533  read_ternary (fp, inex_im);
534  read_mpc (fp, expected, signs);
535  read_mpc (fp, op1, NULL);
536  read_uint (fp, op2);
537  read_mpc_rounding_mode (fp, rnd);
538  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
539  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
540}
541
542static void
543read_ccs (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
544          known_signs_t *signs, mpc_ptr op1, long int *op2, mpc_rnd_t *rnd)
545{
546  test_line_number = line_number;
547  read_ternary (fp, inex_re);
548  read_ternary (fp, inex_im);
549  read_mpc (fp, expected, signs);
550  read_mpc (fp, op1, NULL);
551  read_sint (fp, op2);
552  read_mpc_rounding_mode (fp, rnd);
553  check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
554  check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
555}
556
557/* set MPFR flags to random values */
558static void
559set_mpfr_flags (int counter)
560{
561  if (counter & 1)
562    mpfr_set_underflow ();
563  else
564    mpfr_clear_underflow ();
565  if (counter & 2)
566    mpfr_set_overflow ();
567  else
568    mpfr_clear_overflow ();
569  /* the divide-by-0 flag was added in MPFR 3.1.0 */
570#ifdef mpfr_set_divby0
571  if (counter & 4)
572    mpfr_set_divby0 ();
573  else
574    mpfr_clear_divby0 ();
575#endif
576  if (counter & 8)
577    mpfr_set_nanflag ();
578  else
579    mpfr_clear_nanflag ();
580  if (counter & 16)
581    mpfr_set_inexflag ();
582  else
583    mpfr_clear_inexflag ();
584  if (counter & 32)
585    mpfr_set_erangeflag ();
586  else
587    mpfr_clear_erangeflag ();
588}
589
590/* Check MPFR flags: we allow that some flags are set internally by MPC,
591   for example if MPC does internal computations (using MPFR) which yield
592   an overflow, even if the final MPC result fits in the exponent range.
593   However we don't allow MPC to *clear* the MPFR flags */
594static void
595check_mpfr_flags (int counter)
596{
597  int old, neu;
598
599  old = (counter & 1) != 0;
600  neu = mpfr_underflow_p () != 0;
601  if (old && (neu == 0))
602    {
603      printf ("Error, underflow flag has been modified from %d to %d\n",
604              old, neu);
605      exit (1);
606    }
607  old = (counter & 2) != 0;
608  neu = mpfr_overflow_p () != 0;
609  if (old && (neu == 0))
610    {
611      printf ("Error, overflow flag has been modified from %d to %d\n",
612              old, neu);
613      exit (1);
614    }
615#ifdef mpfr_divby0_p
616  old = (counter & 4) != 0;
617  neu = mpfr_divby0_p () != 0;
618  if (old && (neu == 0))
619    {
620      printf ("Error, divby0 flag has been modified from %d to %d\n",
621              old, neu);
622      exit (1);
623    }
624#endif
625  old = (counter & 8) != 0;
626  neu = mpfr_nanflag_p () != 0;
627  if (old && (neu == 0))
628    {
629      printf ("Error, nanflag flag has been modified from %d to %d\n",
630              old, neu);
631      exit (1);
632    }
633  old = (counter & 16) != 0;
634  neu = mpfr_inexflag_p () != 0;
635  if (old && (neu == 0))
636    {
637      printf ("Error, inexflag flag has been modified from %d to %d\n",
638              old, neu);
639      exit (1);
640    }
641  old = (counter & 32) != 0;
642  neu = mpfr_erangeflag_p () != 0;
643  if (old && (neu == 0))
644    {
645      printf ("Error, erangeflag flag has been modified from %d to %d\n",
646              old, neu);
647      exit (1);
648    }
649}
650
651/* data_check (function, data_file_name) checks function results against
652 precomputed data in a file.*/
653void
654data_check (mpc_function function, const char *file_name)
655{
656  FILE *fp;
657
658  int inex_re;
659  mpfr_t x1, x2;
660  mpfr_rnd_t mpfr_rnd = GMP_RNDN;
661  int sign_real;
662
663  int inex_im;
664  mpc_t z1, z2, z3, z4, z5;
665  mpc_rnd_t rnd = MPC_RNDNN;
666
667  unsigned long int ui;
668  long int si;
669
670  known_signs_t signs;
671  int inex = 0;
672
673  static int rand_counter = 0;
674
675  fp = open_data_file (file_name);
676
677  /* 1. init needed variables */
678  mpc_init2 (z1, 2);
679  switch (function.type)
680    {
681    case FC:
682      mpfr_init (x1);
683      mpfr_init (x2);
684      break;
685    case CC: case CCU: case CCS:
686      mpc_init2 (z2, 2);
687      mpc_init2 (z3, 2);
688      break;
689    case C_CC:
690      mpc_init2 (z2, 2);
691      mpc_init2 (z3, 2);
692      mpc_init2 (z4, 2);
693      break;
694    case CCCC:
695      mpc_init2 (z2, 2);
696      mpc_init2 (z3, 2);
697      mpc_init2 (z4, 2);
698      mpc_init2 (z5, 2);
699      break;
700    case CFC: case CCF:
701      mpfr_init (x1);
702      mpc_init2 (z2, 2);
703      mpc_init2 (z3, 2);
704      break;
705    default:
706      ;
707    }
708
709  /* 2. read data file */
710  line_number = 1;
711  nextchar = getc (fp);
712  skip_whitespace_comments (fp);
713  while (nextchar != EOF) {
714      set_mpfr_flags (rand_counter);
715
716      /* for each kind of function prototype: */
717      /* 3.1 read a line of data: expected result, parameters, rounding mode */
718      /* 3.2 compute function at the same precision as the expected result */
719      /* 3.3 compare this result with the expected one */
720      switch (function.type)
721        {
722        case FC: /* example mpc_norm */
723          read_fc (fp, &inex_re, x1, &sign_real, z1, &mpfr_rnd);
724          mpfr_set_prec (x2, mpfr_get_prec (x1));
725          inex = function.pointer.FC (x2, z1, mpfr_rnd);
726          if ((inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
727              || !same_mpfr_value (x1, x2, sign_real))
728            {
729              mpfr_t got, expected;
730              mpc_t op;
731              op[0] = z1[0];
732              got[0] = x2[0];
733              expected[0] = x1[0];
734              printf ("%s(op) failed (%s:%lu)\nwith rounding mode %s\n",
735                      function.name, file_name, test_line_number,
736                      mpfr_rnd_mode[mpfr_rnd]);
737              if (inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
738                printf("ternary value: got %s, expected %s\n",
739                       MPFR_INEX_STR (inex), MPFR_INEX_STR (inex_re));
740              MPC_OUT (op);
741              printf ("     ");
742              MPFR_OUT (got);
743              MPFR_OUT (expected);
744
745              exit (1);
746            }
747          break;
748
749        case CC: /* example mpc_log */
750          read_cc (fp, &inex_re, &inex_im, z1, &signs, z2, &rnd);
751          mpfr_set_prec (mpc_realref (z3), MPC_PREC_RE (z1));
752          mpfr_set_prec (mpc_imagref (z3), MPC_PREC_IM (z1));
753          inex = function.pointer.CC (z3, z2, rnd);
754          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
755              || !same_mpc_value (z3, z1, signs))
756            {
757              mpc_t op, got, expected; /* display sensible variable names */
758              op[0] = z2[0];
759              expected[0]= z1[0];
760              got[0] = z3[0];
761              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
762                      function.name, test_line_number, rnd_mode[rnd]);
763              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
764                printf("ternary value: got %s, expected (%s, %s)\n",
765                       MPC_INEX_STR (inex),
766                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
767              MPC_OUT (op);
768              printf ("     ");
769              MPC_OUT (got);
770              MPC_OUT (expected);
771
772              exit (1);
773            }
774          break;
775
776        case C_CC: /* example mpc_mul */
777          read_ccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, &rnd);
778          mpfr_set_prec (mpc_realref(z4), MPC_PREC_RE (z1));
779          mpfr_set_prec (mpc_imagref(z4), MPC_PREC_IM (z1));
780          inex = function.pointer.C_CC (z4, z2, z3, rnd);
781          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
782              || !same_mpc_value (z4, z1, signs))
783            {
784              /* display sensible variable names */
785              mpc_t op1, op2, got, expected;
786              op1[0] = z2[0];
787              op2[0] = z3[0];
788              expected[0]= z1[0];
789              got[0] = z4[0];
790              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
791                      function.name, test_line_number, rnd_mode[rnd]);
792              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
793                printf("ternary value: got %s, expected (%s, %s)\n",
794                       MPC_INEX_STR (inex),
795                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
796              MPC_OUT (op1);
797              MPC_OUT (op2);
798              printf ("     ");
799              MPC_OUT (got);
800              MPC_OUT (expected);
801
802              exit (1);
803            }
804          if (function.properties & FUNC_PROP_SYMETRIC)
805            {
806              inex = function.pointer.C_CC (z4, z3, z2, rnd);
807              if (!MPC_INEX_CMP (inex_re, inex_im, inex)
808              || !same_mpc_value (z4, z1, signs))
809                {
810                  /* display sensible variable names */
811                  mpc_t op1, op2, got, expected;
812                  op1[0] = z3[0];
813                  op2[0] = z2[0];
814                  expected[0]= z1[0];
815                  got[0] = z4[0];
816                  printf ("%s(op) failed (line %lu/symetric test)\n"
817                          "with rounding mode %s\n",
818                          function.name, test_line_number, rnd_mode[rnd]);
819                  if (!MPC_INEX_CMP (inex_re, inex_im, inex))
820                    printf("ternary value: got %s, expected (%s, %s)\n",
821                           MPC_INEX_STR (inex),
822                           MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
823                  MPC_OUT (op1);
824                  MPC_OUT (op2);
825                  printf ("     ");
826                  MPC_OUT (got);
827                  MPC_OUT (expected);
828
829                  exit (1);
830                }
831            }
832          break;
833
834        case CCCC: /* example mpc_fma */
835          read_cccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, z4, &rnd);
836	  /* z1 is the expected value, z2, z3, z4 are the inputs, and z5 is
837	     the computed value */
838          mpfr_set_prec (mpc_realref(z5), MPC_PREC_RE (z1));
839          mpfr_set_prec (mpc_imagref(z5), MPC_PREC_IM (z1));
840          inex = function.pointer.CCCC (z5, z2, z3, z4, rnd);
841          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
842              || !same_mpc_value (z5, z1, signs))
843            {
844              /* display sensible variable names */
845              mpc_t op1, op2, op3, got, expected;
846              op1[0] = z2[0];
847              op2[0] = z3[0];
848              op3[0] = z4[0];
849              expected[0]= z1[0];
850              got[0] = z5[0];
851              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
852                      function.name, test_line_number, rnd_mode[rnd]);
853              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
854                printf("ternary value: got %s, expected (%s, %s)\n",
855                       MPC_INEX_STR (inex),
856                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
857              MPC_OUT (op1);
858              MPC_OUT (op2);
859              MPC_OUT (op3);
860              printf ("     ");
861              MPC_OUT (got);
862              MPC_OUT (expected);
863
864              exit (1);
865            }
866          if (function.properties & FUNC_PROP_SYMETRIC)
867            {
868              inex = function.pointer.CCCC (z5, z3, z2, z4, rnd);
869              if (!MPC_INEX_CMP (inex_re, inex_im, inex)
870              || !same_mpc_value (z5, z1, signs))
871                {
872                  /* display sensible variable names */
873                  mpc_t op1, op2, op3, got, expected;
874                  op1[0] = z3[0];
875                  op2[0] = z2[0];
876		  op3[0] = z4[0];
877                  expected[0]= z1[0];
878                  got[0] = z5[0];
879                  printf ("%s(op) failed (line %lu/symetric test)\n"
880                          "with rounding mode %s\n",
881                          function.name, test_line_number, rnd_mode[rnd]);
882                  if (!MPC_INEX_CMP (inex_re, inex_im, inex))
883                    printf("ternary value: got %s, expected (%s, %s)\n",
884                           MPC_INEX_STR (inex),
885                           MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
886                  MPC_OUT (op1);
887                  MPC_OUT (op2);
888		  MPC_OUT (op3);
889                  printf ("     ");
890                  MPC_OUT (got);
891                  MPC_OUT (expected);
892
893                  exit (1);
894                }
895            }
896          break;
897
898        case CFC: /* example mpc_fr_div */
899          read_cfc (fp, &inex_re, &inex_im, z1, &signs, x1, z2, &rnd);
900          mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
901          mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
902          inex = function.pointer.CFC (z3, x1, z2, rnd);
903          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
904              || !same_mpc_value (z3, z1, signs))
905            {
906              /* display sensible variable names */
907              mpc_t op2, got, expected;
908              mpfr_t op1;
909              op1[0] = x1[0];
910              op2[0] = z2[0];
911              expected[0]= z1[0];
912              got[0] = z3[0];
913              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
914                      function.name, test_line_number, rnd_mode[rnd]);
915              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
916                printf("ternary value: got %s, expected (%s, %s)\n",
917                       MPC_INEX_STR (inex),
918                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
919              MPFR_OUT (op1);
920              MPC_OUT (op2);
921              printf ("     ");
922              MPC_OUT (got);
923              MPC_OUT (expected);
924
925              exit (1);
926            }
927          break;
928
929        case CCF: /* example mpc_mul_fr */
930          read_ccf (fp, &inex_re, &inex_im, z1, &signs, z2, x1, &rnd);
931          mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
932          mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
933          inex = function.pointer.CCF (z3, z2, x1, rnd);
934          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
935              || !same_mpc_value (z3, z1, signs))
936            {
937              /* display sensible variable names */
938              mpc_t op1, got, expected;
939              mpfr_t op2;
940              op1[0] = z2[0];
941              op2[0] = x1[0];
942              expected[0]= z1[0];
943              got[0] = z3[0];
944              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
945                      function.name, test_line_number, rnd_mode[rnd]);
946              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
947                printf("ternary value: got %s, expected (%s, %s)\n",
948                       MPC_INEX_STR (inex),
949                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
950              MPC_OUT (op1);
951              MPFR_OUT (op2);
952              printf ("     ");
953              MPC_OUT (got);
954              MPC_OUT (expected);
955
956              exit (1);
957            }
958          break;
959
960        case CCU: /* example mpc_pow_ui */
961          read_ccu (fp, &inex_re, &inex_im, z1, &signs, z2, &ui, &rnd);
962          mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
963          mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
964          inex = function.pointer.CCU (z3, z2, ui, rnd);
965          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
966              || !same_mpc_value (z3, z1, signs))
967            {
968              /* display sensible variable names */
969              mpc_t op1, got, expected;
970              op1[0] = z2[0];
971              expected[0]= z1[0];
972              got[0] = z3[0];
973              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
974                      function.name, test_line_number, rnd_mode[rnd]);
975              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
976                printf("ternary value: got %s, expected (%s, %s)\n",
977                       MPC_INEX_STR (inex),
978                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
979              MPC_OUT (op1);
980              printf ("op2 %lu\n     ", ui);
981              MPC_OUT (got);
982              MPC_OUT (expected);
983
984              exit (1);
985            }
986          break;
987
988        case CCS: /* example mpc_pow_si */
989          read_ccs (fp, &inex_re, &inex_im, z1, &signs, z2, &si, &rnd);
990          mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
991          mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
992          inex = function.pointer.CCS (z3, z2, si, rnd);
993          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
994              || !same_mpc_value (z3, z1, signs))
995            {
996              /* display sensible variable names */
997              mpc_t op1, got, expected;
998              op1[0] = z2[0];
999              expected[0]= z1[0];
1000              got[0] = z3[0];
1001              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
1002                      function.name, test_line_number, rnd_mode[rnd]);
1003              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
1004                printf("ternary value: got %s, expected (%s, %s)\n",
1005                       MPC_INEX_STR (inex),
1006                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
1007              MPC_OUT (op1);
1008              printf ("op2 %li\n     ", si);
1009              MPC_OUT (got);
1010              MPC_OUT (expected);
1011
1012              exit (1);
1013            }
1014          break;
1015
1016        default:
1017          printf ("Unhandled function prototype %i in 'data_check'\n", function.type);
1018          exit (1);
1019        }
1020
1021      /* check MPFR flags were not modified */
1022      check_mpfr_flags (rand_counter);
1023      rand_counter ++;
1024    }
1025
1026  /* 3. Clear used variables */
1027  mpc_clear (z1);
1028  switch (function.type)
1029    {
1030    case FC:
1031      mpfr_clear (x1);
1032      mpfr_clear (x2);
1033      break;
1034    case CC: case CCU: case CCS:
1035      mpc_clear (z2);
1036      mpc_clear (z3);
1037      break;
1038    case C_CC:
1039      mpc_clear (z2);
1040      mpc_clear (z3);
1041      mpc_clear (z4);
1042      break;
1043    case CCCC:
1044      mpc_clear (z2);
1045      mpc_clear (z3);
1046      mpc_clear (z4);
1047      mpc_clear (z5);
1048      break;
1049    case CFC: case CCF:
1050      mpfr_clear (x1);
1051      mpc_clear (z2);
1052      mpc_clear (z3);
1053      break;
1054    default:
1055      ;
1056    }
1057
1058  close_data_file (fp);
1059}
1060