1/* Read data file and check function.
2
3Copyright (C) INRIA, 2008, 2009, 2010, 2011
4
5This file is part of the MPC Library.
6
7The MPC Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 2.1 of the License, or (at your
10option) any later version.
11
12The MPC Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the MPC Library; see the file COPYING.LIB.  If not, write to
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20MA 02111-1307, USA. */
21
22#include <stdlib.h>
23#include <string.h>
24#include "mpc-tests.h"
25
26char *pathname;
27unsigned long line_number;
28   /* file name with complete path and currently read line;
29      kept globally to simplify parameter passing */
30unsigned long test_line_number;
31   /* start line of data test (which may extend over several lines) */
32int nextchar;
33   /* character appearing next in the file, may be EOF */
34
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)))
38
39#define MPFR_INEX_STR(inex)                     \
40  (inex) == TERNARY_NOT_CHECKED ? "?"           \
41    : (inex) == +1 ? "+1"                       \
42    : (inex) == -1 ? "-1" : "0"
43
44static const char *mpfr_rnd_mode [] =
45  { "GMP_RNDN", "GMP_RNDZ", "GMP_RNDU", "GMP_RNDD" };
46
47const 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",
64  };
65
66/* file functions */
67FILE *
68open_data_file (const char *file_name)
69{
70  FILE *fp;
71  char *src_dir;
72  char default_srcdir[] = ".";
73
74  src_dir = getenv ("srcdir");
75  if (src_dir == NULL)
76    src_dir = default_srcdir;
77
78  pathname = (char *) malloc ((strlen (src_dir)) + strlen (file_name) + 2);
79  if (pathname == NULL)
80    {
81      printf ("Cannot allocate memory\n");
82      exit (1);
83    }
84  sprintf (pathname, "%s/%s", src_dir, file_name);
85  fp = fopen (pathname, "r");
86  if (fp == NULL)
87    {
88      fprintf (stderr, "Unable to open %s\n", pathname);
89      exit (1);
90    }
91
92  return fp;
93}
94
95void
96close_data_file (FILE *fp)
97{
98  free (pathname);
99  fclose (fp);
100}
101
102/* read primitives */
103static void
104skip_line (FILE *fp)
105   /* skips characters until reaching '\n' or EOF; */
106   /* '\n' is skipped as well                      */
107{
108   while (nextchar != EOF && nextchar != '\n')
109     nextchar = getc (fp);
110   if (nextchar != EOF)
111     {
112       line_number ++;
113       nextchar = getc (fp);
114     }
115}
116
117static void
118skip_whitespace (FILE *fp)
119   /* skips over whitespace if any until reaching EOF */
120   /* or non-whitespace                               */
121{
122   while (isspace (nextchar))
123     {
124       if (nextchar == '\n')
125         line_number ++;
126       nextchar = getc (fp);
127     }
128}
129
130void
131skip_whitespace_comments (FILE *fp)
132   /* skips over all whitespace and comments, if any */
133{
134   skip_whitespace (fp);
135   while (nextchar == '#') {
136      skip_line (fp);
137      if (nextchar != EOF)
138         skip_whitespace (fp);
139   }
140}
141
142
143size_t
144read_string (FILE *fp, char **buffer_ptr, size_t buffer_length, const char *name)
145{
146  size_t pos;
147  char *buffer;
148
149  pos = 0;
150  buffer = *buffer_ptr;
151
152  if (nextchar == '"')
153    nextchar = getc (fp);
154  else
155    goto error;
156
157  while (nextchar != EOF && nextchar != '"')
158    {
159      if (nextchar == '\n')
160        line_number ++;
161      if (pos + 1 > buffer_length)
162        {
163          buffer = (char *) realloc (buffer, 2 * buffer_length);
164          if (buffer == NULL)
165            {
166              printf ("Cannot allocate memory\n");
167              exit (1);
168            }
169          buffer_length *= 2;
170        }
171      buffer[pos++] = (char) nextchar;
172      nextchar = getc (fp);
173    }
174
175  if (nextchar != '"')
176    goto error;
177
178  if (pos + 1 > buffer_length)
179    {
180      buffer = (char *) realloc (buffer, buffer_length + 1);
181      if (buffer == NULL)
182        {
183          printf ("Cannot allocate memory\n");
184          exit (1);
185        }
186      buffer_length *= 2;
187    }
188  buffer[pos] = '\0';
189
190  nextchar = getc (fp);
191  skip_whitespace_comments (fp);
192
193  buffer_ptr = &buffer;
194
195  return buffer_length;
196
197 error:
198  printf ("Error: Unable to read %s in file '%s' line '%lu'\n",
199          name, pathname, line_number);
200  exit (1);
201}
202
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.                                        */
206void
207read_ternary (FILE *fp, int* ternary)
208{
209  switch (nextchar)
210    {
211    case '!':
212      *ternary = TERNARY_ERROR;
213      break;
214    case '?':
215      *ternary = TERNARY_NOT_CHECKED;
216      break;
217    case '+':
218      *ternary = +1;
219      break;
220    case '0':
221      *ternary = 0;
222      break;
223    case '-':
224      *ternary = -1;
225      break;
226    default:
227      printf ("Error: Unexpected ternary value '%c' in file '%s' line %lu\n",
228              nextchar, pathname, line_number);
229      exit (1);
230    }
231
232  nextchar = getc (fp);
233  skip_whitespace_comments (fp);
234}
235
236void
237read_mpfr_rounding_mode (FILE *fp, mpfr_rnd_t* rnd)
238{
239  switch (nextchar)
240    {
241    case 'n': case 'N':
242      *rnd = GMP_RNDN;
243      break;
244    case 'z': case 'Z':
245      *rnd = GMP_RNDZ;
246      break;
247    case 'u': case 'U':
248      *rnd = GMP_RNDU;
249      break;
250    case 'd': case 'D':
251      *rnd = GMP_RNDD;
252      break;
253    default:
254      printf ("Error: Unexpected rounding mode '%c' in file '%s' line %lu\n",
255              nextchar, pathname, line_number);
256      exit (1);
257    }
258
259    nextchar = getc (fp);
260    if (nextchar != EOF && !isspace (nextchar)) {
261      printf ("Error: Rounding mode not followed by white space in file "
262              "'%s' line %lu\n",
263              pathname, line_number);
264      exit (1);
265    }
266    skip_whitespace_comments (fp);
267}
268
269void
270read_mpc_rounding_mode (FILE *fp, mpc_rnd_t* rnd)
271{
272   mpfr_rnd_t re, im;
273   read_mpfr_rounding_mode (fp, &re);
274   read_mpfr_rounding_mode (fp, &im);
275   *rnd = RNDC (re, im);
276}
277
278void
279read_int (FILE *fp, int *nread, const char *name)
280{
281  int n = 0;
282
283  if (nextchar == EOF)
284    {
285      printf ("Error: Unexpected EOF when reading int "
286              "in file '%s' line %lu\n",
287              pathname, line_number);
288      exit (1);
289    }
290  ungetc (nextchar, fp);
291  n = fscanf (fp, "%i", nread);
292  if (ferror (fp) || n == 0 || n == EOF)
293    {
294      printf ("Error: Cannot read %s in file '%s' line %lu\n",
295              name, pathname, line_number);
296      exit (1);
297    }
298  nextchar = getc (fp);
299  skip_whitespace_comments (fp);
300}
301
302static void
303read_uint (FILE *fp, unsigned long int *ui)
304{
305  int n = 0;
306
307  if (nextchar == EOF)
308    {
309      printf ("Error: Unexpected EOF when reading uint "
310              "in file '%s' line %lu\n",
311              pathname, line_number);
312      exit (1);
313    }
314  ungetc (nextchar, fp);
315  n = fscanf (fp, "%lu", ui);
316  if (ferror (fp) || n == 0 || n == EOF)
317    {
318      printf ("Error: Cannot read uint in file '%s' line %lu\n",
319              pathname, line_number);
320      exit (1);
321    }
322  nextchar = getc (fp);
323  skip_whitespace_comments (fp);
324}
325
326mpfr_prec_t
327read_mpfr_prec (FILE *fp)
328{
329   unsigned long prec;
330   int n;
331
332   if (nextchar == EOF) {
333      printf ("Error: Unexpected EOF when reading mpfr precision "
334              "in file '%s' line %lu\n",
335              pathname, line_number);
336      exit (1);
337   }
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);
345      exit (1);
346   }
347   nextchar = getc (fp);
348   skip_whitespace_comments (fp);
349   return (mpfr_prec_t) prec;
350}
351
352static void
353read_mpfr_mantissa (FILE *fp, mpfr_ptr x)
354{
355   if (nextchar == EOF) {
356      printf ("Error: Unexpected EOF when reading mpfr mantissa "
357              "in file '%s' line %lu\n",
358              pathname, line_number);
359      exit (1);
360   }
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);
366      exit (1);
367   }
368   nextchar = getc (fp);
369   skip_whitespace_comments (fp);
370}
371
372void
373read_mpfr (FILE *fp, mpfr_ptr x, int *known_sign)
374{
375   int sign;
376   mpfr_set_prec (x, read_mpfr_prec (fp));
377   sign = nextchar;
378   read_mpfr_mantissa (fp, x);
379
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)
384     *known_sign =
385       (!mpfr_zero_p (x) && !mpfr_inf_p (x))
386       || sign == '+' || sign == '-';
387}
388
389void
390read_mpc (FILE *fp, mpc_ptr z, known_signs_t *ks)
391{
392  read_mpfr (fp, MPC_RE (z), ks == NULL ? NULL : &ks->re);
393  read_mpfr (fp, MPC_IM (z), ks == NULL ? NULL : &ks->im);
394}
395
396static void
397check_compatible (int inex, mpfr_t expected, mpfr_rnd_t rnd, const char *s)
398{
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))
403    {
404      if (s != NULL)
405        printf ("Incompatible ternary value '%c' (%s part) in file '%s' line %lu\n",
406              (inex == 1) ? '+' : '-', s, pathname, test_line_number);
407      else
408        printf ("Incompatible ternary value '%c' in file '%s' line %lu\n",
409              (inex == 1) ? '+' : '-', pathname, test_line_number);
410    }
411}
412
413/* read lines of data */
414static void
415read_cc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
416         known_signs_t *signs, mpc_ptr op, mpc_rnd_t *rnd)
417{
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");
426}
427
428static void
429read_fc (FILE *fp, int *inex, mpfr_ptr expected, int *sign, mpc_ptr op,
430         mpfr_rnd_t *rnd)
431{
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);
438}
439
440static void
441read_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)
443{
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");
453}
454
455/* read lines of data for function with three mpc_t inputs and one mpc_t
456   output like mpc_fma */
457static void
458read_cccc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
459	   known_signs_t *signs, mpc_ptr op1, mpc_ptr op2, mpc_ptr op3,
460	   mpc_rnd_t *rnd)
461{
462  test_line_number = line_number;
463  read_ternary (fp, inex_re);
464  read_ternary (fp, inex_im);
465  read_mpc (fp, expected, signs);
466  read_mpc (fp, op1, NULL);
467  read_mpc (fp, op2, NULL);
468  read_mpc (fp, op3, NULL);
469  read_mpc_rounding_mode (fp, rnd);
470  check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
471  check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
472}
473
474static void
475read_cfc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
476          known_signs_t *signs, mpfr_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
477{
478  test_line_number = line_number;
479  read_ternary (fp, inex_re);
480  read_ternary (fp, inex_im);
481  read_mpc (fp, expected, signs);
482  read_mpfr (fp, op1, NULL);
483  read_mpc (fp, op2, NULL);
484  read_mpc_rounding_mode (fp, rnd);
485  check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
486  check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
487}
488
489static void
490read_ccf (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
491          known_signs_t *signs, mpc_ptr op1, mpfr_ptr op2, mpc_rnd_t *rnd)
492{
493  test_line_number = line_number;
494  read_ternary (fp, inex_re);
495  read_ternary (fp, inex_im);
496  read_mpc (fp, expected, signs);
497  read_mpc (fp, op1, NULL);
498  read_mpfr (fp, op2, NULL);
499  read_mpc_rounding_mode (fp, rnd);
500  check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
501  check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
502}
503
504static void
505read_ccu (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
506          known_signs_t *signs, mpc_ptr op1, unsigned long int *op2, mpc_rnd_t *rnd)
507{
508  test_line_number = line_number;
509  read_ternary (fp, inex_re);
510  read_ternary (fp, inex_im);
511  read_mpc (fp, expected, signs);
512  read_mpc (fp, op1, NULL);
513  read_uint (fp, op2);
514  read_mpc_rounding_mode (fp, rnd);
515  check_compatible (*inex_re, MPC_RE(expected), MPC_RND_RE(*rnd), "real");
516  check_compatible (*inex_im, MPC_IM(expected), MPC_RND_IM(*rnd), "imag");
517}
518
519/* data_check (function, data_file_name) checks function results against
520 precomputed data in a file.*/
521void
522data_check (mpc_function function, const char *file_name)
523{
524  FILE *fp;
525
526  int inex_re;
527  mpfr_t x1, x2;
528  mpfr_rnd_t mpfr_rnd = GMP_RNDN;
529  int sign_real;
530
531  int inex_im;
532  mpc_t z1, z2, z3, z4, z5;
533  mpc_rnd_t rnd = MPC_RNDNN;
534
535  unsigned long int ui;
536
537  known_signs_t signs;
538  int inex = 0;
539
540  fp = open_data_file (file_name);
541
542  /* 1. init needed variables */
543  mpc_init2 (z1, 2);
544  switch (function.type)
545    {
546    case FC:
547      mpfr_init (x1);
548      mpfr_init (x2);
549      break;
550    case CC: case CCU:
551      mpc_init2 (z2, 2);
552      mpc_init2 (z3, 2);
553      break;
554    case C_CC:
555      mpc_init2 (z2, 2);
556      mpc_init2 (z3, 2);
557      mpc_init2 (z4, 2);
558      break;
559    case CCCC:
560      mpc_init2 (z2, 2);
561      mpc_init2 (z3, 2);
562      mpc_init2 (z4, 2);
563      mpc_init2 (z5, 2);
564      break;
565    case CFC: case CCF:
566      mpfr_init (x1);
567      mpc_init2 (z2, 2);
568      mpc_init2 (z3, 2);
569      break;
570    default:
571      ;
572    }
573
574  /* 2. read data file */
575  line_number = 1;
576  nextchar = getc (fp);
577  skip_whitespace_comments (fp);
578  while (nextchar != EOF) {
579      /* for each kind of function prototype: */
580      /* 3.1 read a line of data: expected result, parameters, rounding mode */
581      /* 3.2 compute function at the same precision as the expected result */
582      /* 3.3 compare this result with the expected one */
583      switch (function.type)
584        {
585        case FC: /* example mpc_norm */
586          read_fc (fp, &inex_re, x1, &sign_real, z1, &mpfr_rnd);
587          mpfr_set_prec (x2, mpfr_get_prec (x1));
588          inex = function.pointer.FC (x2, z1, mpfr_rnd);
589          if ((inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
590              || !same_mpfr_value (x1, x2, sign_real))
591            {
592              mpfr_t got, expected;
593              mpc_t op;
594              op[0] = z1[0];
595              got[0] = x2[0];
596              expected[0] = x1[0];
597              printf ("%s(op) failed (%s:%lu)\nwith rounding mode %s\n",
598                      function.name, file_name, test_line_number,
599                      mpfr_rnd_mode[mpfr_rnd]);
600              if (inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
601                printf("ternary value: got %s, expected %s\n",
602                       MPFR_INEX_STR (inex), MPFR_INEX_STR (inex_re));
603              MPC_OUT (op);
604              printf ("     ");
605              MPFR_OUT (got);
606              MPFR_OUT (expected);
607
608              exit (1);
609            }
610          break;
611
612        case CC: /* example mpc_log */
613          read_cc (fp, &inex_re, &inex_im, z1, &signs, z2, &rnd);
614          mpfr_set_prec (MPC_RE (z3), MPC_PREC_RE (z1));
615          mpfr_set_prec (MPC_IM (z3), MPC_PREC_IM (z1));
616          inex = function.pointer.CC (z3, z2, rnd);
617          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
618              || !same_mpc_value (z3, z1, signs))
619            {
620              mpc_t op, got, expected; /* display sensible variable names */
621              op[0] = z2[0];
622              expected[0]= z1[0];
623              got[0] = z3[0];
624              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
625                      function.name, test_line_number, rnd_mode[rnd]);
626              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
627                printf("ternary value: got %s, expected (%s, %s)\n",
628                       MPC_INEX_STR (inex),
629                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
630              MPC_OUT (op);
631              printf ("     ");
632              MPC_OUT (got);
633              MPC_OUT (expected);
634
635              exit (1);
636            }
637          break;
638
639        case C_CC: /* example mpc_mul */
640          read_ccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, &rnd);
641          mpfr_set_prec (MPC_RE(z4), MPC_PREC_RE (z1));
642          mpfr_set_prec (MPC_IM(z4), MPC_PREC_IM (z1));
643          inex = function.pointer.C_CC (z4, z2, z3, rnd);
644          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
645              || !same_mpc_value (z4, z1, signs))
646            {
647              /* display sensible variable names */
648              mpc_t op1, op2, got, expected;
649              op1[0] = z2[0];
650              op2[0] = z3[0];
651              expected[0]= z1[0];
652              got[0] = z4[0];
653              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
654                      function.name, test_line_number, rnd_mode[rnd]);
655              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
656                printf("ternary value: got %s, expected (%s, %s)\n",
657                       MPC_INEX_STR (inex),
658                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
659              MPC_OUT (op1);
660              MPC_OUT (op2);
661              printf ("     ");
662              MPC_OUT (got);
663              MPC_OUT (expected);
664
665              exit (1);
666            }
667          if (function.properties & FUNC_PROP_SYMETRIC)
668            {
669              inex = function.pointer.C_CC (z4, z3, z2, rnd);
670              if (!MPC_INEX_CMP (inex_re, inex_im, inex)
671              || !same_mpc_value (z4, z1, signs))
672                {
673                  /* display sensible variable names */
674                  mpc_t op1, op2, got, expected;
675                  op1[0] = z3[0];
676                  op2[0] = z2[0];
677                  expected[0]= z1[0];
678                  got[0] = z4[0];
679                  printf ("%s(op) failed (line %lu/symetric test)\n"
680                          "with rounding mode %s\n",
681                          function.name, test_line_number, rnd_mode[rnd]);
682                  if (!MPC_INEX_CMP (inex_re, inex_im, inex))
683                    printf("ternary value: got %s, expected (%s, %s)\n",
684                           MPC_INEX_STR (inex),
685                           MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
686                  MPC_OUT (op1);
687                  MPC_OUT (op2);
688                  printf ("     ");
689                  MPC_OUT (got);
690                  MPC_OUT (expected);
691
692                  exit (1);
693                }
694            }
695          break;
696
697        case CCCC: /* example mpc_fma */
698          read_cccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, z4, &rnd);
699	  /* z1 is the expected value, z2, z3, z4 are the inputs, and z5 is
700	     the computed value */
701          mpfr_set_prec (MPC_RE(z5), MPC_PREC_RE (z1));
702          mpfr_set_prec (MPC_IM(z5), MPC_PREC_IM (z1));
703          inex = function.pointer.CCCC (z5, z2, z3, z4, rnd);
704          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
705              || !same_mpc_value (z5, z1, signs))
706            {
707              /* display sensible variable names */
708              mpc_t op1, op2, op3, got, expected;
709              op1[0] = z2[0];
710              op2[0] = z3[0];
711              op3[0] = z4[0];
712              expected[0]= z1[0];
713              got[0] = z5[0];
714              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
715                      function.name, test_line_number, rnd_mode[rnd]);
716              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
717                printf("ternary value: got %s, expected (%s, %s)\n",
718                       MPC_INEX_STR (inex),
719                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
720              MPC_OUT (op1);
721              MPC_OUT (op2);
722              MPC_OUT (op3);
723              printf ("     ");
724              MPC_OUT (got);
725              MPC_OUT (expected);
726
727              exit (1);
728            }
729          if (function.properties & FUNC_PROP_SYMETRIC)
730            {
731              inex = function.pointer.CCCC (z5, z3, z2, z4, rnd);
732              if (!MPC_INEX_CMP (inex_re, inex_im, inex)
733              || !same_mpc_value (z5, z1, signs))
734                {
735                  /* display sensible variable names */
736                  mpc_t op1, op2, op3, got, expected;
737                  op1[0] = z3[0];
738                  op2[0] = z2[0];
739		  op3[0] = z4[0];
740                  expected[0]= z1[0];
741                  got[0] = z5[0];
742                  printf ("%s(op) failed (line %lu/symetric test)\n"
743                          "with rounding mode %s\n",
744                          function.name, test_line_number, rnd_mode[rnd]);
745                  if (!MPC_INEX_CMP (inex_re, inex_im, inex))
746                    printf("ternary value: got %s, expected (%s, %s)\n",
747                           MPC_INEX_STR (inex),
748                           MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
749                  MPC_OUT (op1);
750                  MPC_OUT (op2);
751		  MPC_OUT (op3);
752                  printf ("     ");
753                  MPC_OUT (got);
754                  MPC_OUT (expected);
755
756                  exit (1);
757                }
758            }
759          break;
760
761        case CFC: /* example mpc_fr_div */
762          read_cfc (fp, &inex_re, &inex_im, z1, &signs, x1, z2, &rnd);
763          mpfr_set_prec (MPC_RE(z3), MPC_PREC_RE (z1));
764          mpfr_set_prec (MPC_IM(z3), MPC_PREC_IM (z1));
765          inex = function.pointer.CFC (z3, x1, z2, rnd);
766          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
767              || !same_mpc_value (z3, z1, signs))
768            {
769              /* display sensible variable names */
770              mpc_t op2, got, expected;
771              mpfr_t op1;
772              op1[0] = x1[0];
773              op2[0] = z2[0];
774              expected[0]= z1[0];
775              got[0] = z3[0];
776              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
777                      function.name, test_line_number, rnd_mode[rnd]);
778              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
779                printf("ternary value: got %s, expected (%s, %s)\n",
780                       MPC_INEX_STR (inex),
781                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
782              MPFR_OUT (op1);
783              MPC_OUT (op2);
784              printf ("     ");
785              MPC_OUT (got);
786              MPC_OUT (expected);
787
788              exit (1);
789            }
790          break;
791
792        case CCF: /* example mpc_mul_fr */
793          read_ccf (fp, &inex_re, &inex_im, z1, &signs, z2, x1, &rnd);
794          mpfr_set_prec (MPC_RE(z3), MPC_PREC_RE (z1));
795          mpfr_set_prec (MPC_IM(z3), MPC_PREC_IM (z1));
796          inex = function.pointer.CCF (z3, z2, x1, rnd);
797          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
798              || !same_mpc_value (z3, z1, signs))
799            {
800              /* display sensible variable names */
801              mpc_t op1, got, expected;
802              mpfr_t op2;
803              op1[0] = z2[0];
804              op2[0] = x1[0];
805              expected[0]= z1[0];
806              got[0] = z3[0];
807              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
808                      function.name, test_line_number, rnd_mode[rnd]);
809              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
810                printf("ternary value: got %s, expected (%s, %s)\n",
811                       MPC_INEX_STR (inex),
812                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
813              MPC_OUT (op1);
814              MPFR_OUT (op2);
815              printf ("     ");
816              MPC_OUT (got);
817              MPC_OUT (expected);
818
819              exit (1);
820            }
821          break;
822
823        case CCU: /* example mpc_pow_ui */
824          read_ccu (fp, &inex_re, &inex_im, z1, &signs, z2, &ui, &rnd);
825          mpfr_set_prec (MPC_RE(z3), MPC_PREC_RE (z1));
826          mpfr_set_prec (MPC_IM(z3), MPC_PREC_IM (z1));
827          inex = function.pointer.CCU (z3, z2, ui, rnd);
828          if (!MPC_INEX_CMP (inex_re, inex_im, inex)
829              || !same_mpc_value (z3, z1, signs))
830            {
831              /* display sensible variable names */
832              mpc_t op1, got, expected;
833              op1[0] = z2[0];
834              expected[0]= z1[0];
835              got[0] = z3[0];
836              printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
837                      function.name, test_line_number, rnd_mode[rnd]);
838              if (!MPC_INEX_CMP (inex_re, inex_im, inex))
839                printf("ternary value: got %s, expected (%s, %s)\n",
840                       MPC_INEX_STR (inex),
841                       MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
842              MPC_OUT (op1);
843              printf ("op2 %lu\n     ", ui);
844              MPC_OUT (got);
845              MPC_OUT (expected);
846
847              exit (1);
848            }
849          break;
850
851        default:
852          ;
853        }
854    }
855
856  /* 3. Clear used variables */
857  mpc_clear (z1);
858  switch (function.type)
859    {
860    case FC:
861      mpfr_clear (x1);
862      mpfr_clear (x2);
863      break;
864    case CC: case CCU:
865      mpc_clear (z2);
866      mpc_clear (z3);
867      break;
868    case C_CC:
869      mpc_clear (z2);
870      mpc_clear (z3);
871      mpc_clear (z4);
872      break;
873    case CCCC:
874      mpc_clear (z2);
875      mpc_clear (z3);
876      mpc_clear (z4);
877      mpc_clear (z5);
878      break;
879    case CFC: case CCF:
880      mpfr_clear (x1);
881      mpc_clear (z2);
882      mpc_clear (z3);
883      break;
884    default:
885      ;
886    }
887
888  close_data_file (fp);
889}
890