mirror of
https://review.haiku-os.org/buildtools
synced 2025-02-12 08:47:41 +01:00
1060 lines
32 KiB
C
1060 lines
32 KiB
C
/* read_data,c -- Read data file and check function.
|
|
|
|
Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
|
|
|
|
This file is part of GNU MPC.
|
|
|
|
GNU MPC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU Lesser General Public License as published by the
|
|
Free Software Foundation; either version 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see http://www.gnu.org/licenses/ .
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "mpc-tests.h"
|
|
|
|
char *pathname;
|
|
unsigned long line_number;
|
|
/* file name with complete path and currently read line;
|
|
kept globally to simplify parameter passing */
|
|
unsigned long test_line_number;
|
|
/* start line of data test (which may extend over several lines) */
|
|
int nextchar;
|
|
/* character appearing next in the file, may be EOF */
|
|
|
|
#define MPC_INEX_CMP(r, i, c) \
|
|
(((r) == TERNARY_NOT_CHECKED || (r) == MPC_INEX_RE(c)) \
|
|
&& ((i) == TERNARY_NOT_CHECKED || (i) == MPC_INEX_IM (c)))
|
|
|
|
#define MPFR_INEX_STR(inex) \
|
|
(inex) == TERNARY_NOT_CHECKED ? "?" \
|
|
: (inex) == +1 ? "+1" \
|
|
: (inex) == -1 ? "-1" : "0"
|
|
|
|
static const char *mpfr_rnd_mode [] =
|
|
{ "GMP_RNDN", "GMP_RNDZ", "GMP_RNDU", "GMP_RNDD" };
|
|
|
|
const char *rnd_mode[] =
|
|
{ "MPC_RNDNN", "MPC_RNDZN", "MPC_RNDUN", "MPC_RNDDN",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined",
|
|
"MPC_RNDNZ", "MPC_RNDZZ", "MPC_RNDUZ", "MPC_RNDDZ",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined",
|
|
"MPC_RNDNU", "MPC_RNDZU", "MPC_RNDUU", "MPC_RNDDU",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined",
|
|
"MPC_RNDND", "MPC_RNDZD", "MPC_RNDUD", "MPC_RNDDD",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined", "undefined", "undefined", "undefined",
|
|
"undefined", "undefined",
|
|
};
|
|
|
|
/* file functions */
|
|
FILE *
|
|
open_data_file (const char *file_name)
|
|
{
|
|
FILE *fp;
|
|
char *src_dir;
|
|
char default_srcdir[] = ".";
|
|
|
|
src_dir = getenv ("srcdir");
|
|
if (src_dir == NULL)
|
|
src_dir = default_srcdir;
|
|
|
|
pathname = (char *) malloc ((strlen (src_dir)) + strlen (file_name) + 2);
|
|
if (pathname == NULL)
|
|
{
|
|
printf ("Cannot allocate memory\n");
|
|
exit (1);
|
|
}
|
|
sprintf (pathname, "%s/%s", src_dir, file_name);
|
|
fp = fopen (pathname, "r");
|
|
if (fp == NULL)
|
|
{
|
|
fprintf (stderr, "Unable to open %s\n", pathname);
|
|
exit (1);
|
|
}
|
|
|
|
return fp;
|
|
}
|
|
|
|
void
|
|
close_data_file (FILE *fp)
|
|
{
|
|
free (pathname);
|
|
fclose (fp);
|
|
}
|
|
|
|
/* read primitives */
|
|
static void
|
|
skip_line (FILE *fp)
|
|
/* skips characters until reaching '\n' or EOF; */
|
|
/* '\n' is skipped as well */
|
|
{
|
|
while (nextchar != EOF && nextchar != '\n')
|
|
nextchar = getc (fp);
|
|
if (nextchar != EOF)
|
|
{
|
|
line_number ++;
|
|
nextchar = getc (fp);
|
|
}
|
|
}
|
|
|
|
static void
|
|
skip_whitespace (FILE *fp)
|
|
/* skips over whitespace if any until reaching EOF */
|
|
/* or non-whitespace */
|
|
{
|
|
while (isspace (nextchar))
|
|
{
|
|
if (nextchar == '\n')
|
|
line_number ++;
|
|
nextchar = getc (fp);
|
|
}
|
|
}
|
|
|
|
void
|
|
skip_whitespace_comments (FILE *fp)
|
|
/* skips over all whitespace and comments, if any */
|
|
{
|
|
skip_whitespace (fp);
|
|
while (nextchar == '#') {
|
|
skip_line (fp);
|
|
if (nextchar != EOF)
|
|
skip_whitespace (fp);
|
|
}
|
|
}
|
|
|
|
|
|
size_t
|
|
read_string (FILE *fp, char **buffer_ptr, size_t buffer_length, const char *name)
|
|
{
|
|
size_t pos;
|
|
char *buffer;
|
|
|
|
pos = 0;
|
|
buffer = *buffer_ptr;
|
|
|
|
if (nextchar == '"')
|
|
nextchar = getc (fp);
|
|
else
|
|
goto error;
|
|
|
|
while (nextchar != EOF && nextchar != '"')
|
|
{
|
|
if (nextchar == '\n')
|
|
line_number ++;
|
|
if (pos + 1 > buffer_length)
|
|
{
|
|
buffer = (char *) realloc (buffer, 2 * buffer_length);
|
|
if (buffer == NULL)
|
|
{
|
|
printf ("Cannot allocate memory\n");
|
|
exit (1);
|
|
}
|
|
buffer_length *= 2;
|
|
}
|
|
buffer[pos++] = (char) nextchar;
|
|
nextchar = getc (fp);
|
|
}
|
|
|
|
if (nextchar != '"')
|
|
goto error;
|
|
|
|
if (pos + 1 > buffer_length)
|
|
{
|
|
buffer = (char *) realloc (buffer, buffer_length + 1);
|
|
if (buffer == NULL)
|
|
{
|
|
printf ("Cannot allocate memory\n");
|
|
exit (1);
|
|
}
|
|
buffer_length *= 2;
|
|
}
|
|
buffer[pos] = '\0';
|
|
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
|
|
*buffer_ptr = buffer;
|
|
|
|
return buffer_length;
|
|
|
|
error:
|
|
printf ("Error: Unable to read %s in file '%s' line '%lu'\n",
|
|
name, pathname, line_number);
|
|
exit (1);
|
|
}
|
|
|
|
/* All following read routines skip over whitespace and comments; */
|
|
/* so after calling them, nextchar is either EOF or the beginning */
|
|
/* of a non-comment token. */
|
|
void
|
|
read_ternary (FILE *fp, int* ternary)
|
|
{
|
|
switch (nextchar)
|
|
{
|
|
case '!':
|
|
*ternary = TERNARY_ERROR;
|
|
break;
|
|
case '?':
|
|
*ternary = TERNARY_NOT_CHECKED;
|
|
break;
|
|
case '+':
|
|
*ternary = +1;
|
|
break;
|
|
case '0':
|
|
*ternary = 0;
|
|
break;
|
|
case '-':
|
|
*ternary = -1;
|
|
break;
|
|
default:
|
|
printf ("Error: Unexpected ternary value '%c' in file '%s' line %lu\n",
|
|
nextchar, pathname, line_number);
|
|
exit (1);
|
|
}
|
|
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
}
|
|
|
|
void
|
|
read_mpfr_rounding_mode (FILE *fp, mpfr_rnd_t* rnd)
|
|
{
|
|
switch (nextchar)
|
|
{
|
|
case 'n': case 'N':
|
|
*rnd = GMP_RNDN;
|
|
break;
|
|
case 'z': case 'Z':
|
|
*rnd = GMP_RNDZ;
|
|
break;
|
|
case 'u': case 'U':
|
|
*rnd = GMP_RNDU;
|
|
break;
|
|
case 'd': case 'D':
|
|
*rnd = GMP_RNDD;
|
|
break;
|
|
default:
|
|
printf ("Error: Unexpected rounding mode '%c' in file '%s' line %lu\n",
|
|
nextchar, pathname, line_number);
|
|
exit (1);
|
|
}
|
|
|
|
nextchar = getc (fp);
|
|
if (nextchar != EOF && !isspace (nextchar)) {
|
|
printf ("Error: Rounding mode not followed by white space in file "
|
|
"'%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
skip_whitespace_comments (fp);
|
|
}
|
|
|
|
void
|
|
read_mpc_rounding_mode (FILE *fp, mpc_rnd_t* rnd)
|
|
{
|
|
mpfr_rnd_t re, im;
|
|
read_mpfr_rounding_mode (fp, &re);
|
|
read_mpfr_rounding_mode (fp, &im);
|
|
*rnd = MPC_RND (re, im);
|
|
}
|
|
|
|
void
|
|
read_int (FILE *fp, int *nread, const char *name)
|
|
{
|
|
int n = 0;
|
|
|
|
if (nextchar == EOF)
|
|
{
|
|
printf ("Error: Unexpected EOF when reading int "
|
|
"in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
ungetc (nextchar, fp);
|
|
n = fscanf (fp, "%i", nread);
|
|
if (ferror (fp) || n == 0 || n == EOF)
|
|
{
|
|
printf ("Error: Cannot read %s in file '%s' line %lu\n",
|
|
name, pathname, line_number);
|
|
exit (1);
|
|
}
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
}
|
|
|
|
static void
|
|
read_uint (FILE *fp, unsigned long int *ui)
|
|
{
|
|
int n = 0;
|
|
|
|
if (nextchar == EOF)
|
|
{
|
|
printf ("Error: Unexpected EOF when reading uint "
|
|
"in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
ungetc (nextchar, fp);
|
|
n = fscanf (fp, "%lu", ui);
|
|
if (ferror (fp) || n == 0 || n == EOF)
|
|
{
|
|
printf ("Error: Cannot read uint in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
}
|
|
|
|
static void
|
|
read_sint (FILE *fp, long int *si)
|
|
{
|
|
int n = 0;
|
|
|
|
if (nextchar == EOF)
|
|
{
|
|
printf ("Error: Unexpected EOF when reading sint "
|
|
"in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
ungetc (nextchar, fp);
|
|
n = fscanf (fp, "%li", si);
|
|
if (ferror (fp) || n == 0 || n == EOF)
|
|
{
|
|
printf ("Error: Cannot read sint in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
}
|
|
|
|
mpfr_prec_t
|
|
read_mpfr_prec (FILE *fp)
|
|
{
|
|
unsigned long prec;
|
|
int n;
|
|
|
|
if (nextchar == EOF) {
|
|
printf ("Error: Unexpected EOF when reading mpfr precision "
|
|
"in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
ungetc (nextchar, fp);
|
|
n = fscanf (fp, "%lu", &prec);
|
|
if (ferror (fp)) /* then also n == EOF */
|
|
perror ("Error when reading mpfr precision");
|
|
if (n == 0 || n == EOF || prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
|
|
printf ("Error: Impossible mpfr precision in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
return (mpfr_prec_t) prec;
|
|
}
|
|
|
|
static void
|
|
read_mpfr_mantissa (FILE *fp, mpfr_ptr x)
|
|
{
|
|
if (nextchar == EOF) {
|
|
printf ("Error: Unexpected EOF when reading mpfr mantissa "
|
|
"in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
ungetc (nextchar, fp);
|
|
if (mpfr_inp_str (x, fp, 0, GMP_RNDN) == 0) {
|
|
printf ("Error: Impossible to read mpfr mantissa "
|
|
"in file '%s' line %lu\n",
|
|
pathname, line_number);
|
|
exit (1);
|
|
}
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
}
|
|
|
|
void
|
|
read_mpfr (FILE *fp, mpfr_ptr x, int *known_sign)
|
|
{
|
|
int sign;
|
|
mpfr_set_prec (x, read_mpfr_prec (fp));
|
|
sign = nextchar;
|
|
read_mpfr_mantissa (fp, x);
|
|
|
|
/* the sign always matters for regular values ('+' is implicit),
|
|
but when no sign appears before 0 or Inf in the data file, it means
|
|
that only absolute value must be checked. */
|
|
if (known_sign != NULL)
|
|
*known_sign =
|
|
(!mpfr_zero_p (x) && !mpfr_inf_p (x))
|
|
|| sign == '+' || sign == '-';
|
|
}
|
|
|
|
void
|
|
read_mpc (FILE *fp, mpc_ptr z, known_signs_t *ks)
|
|
{
|
|
read_mpfr (fp, mpc_realref (z), ks == NULL ? NULL : &ks->re);
|
|
read_mpfr (fp, mpc_imagref (z), ks == NULL ? NULL : &ks->im);
|
|
}
|
|
|
|
static void
|
|
check_compatible (int inex, mpfr_t expected, mpfr_rnd_t rnd, const char *s)
|
|
{
|
|
if ((rnd == GMP_RNDU && inex == -1) ||
|
|
(rnd == GMP_RNDD && inex == +1) ||
|
|
(rnd == GMP_RNDZ && !mpfr_signbit (expected) && inex == +1) ||
|
|
(rnd == GMP_RNDZ && mpfr_signbit (expected) && inex == -1))
|
|
{
|
|
if (s != NULL)
|
|
printf ("Incompatible ternary value '%c' (%s part) in file '%s' line %lu\n",
|
|
(inex == 1) ? '+' : '-', s, pathname, test_line_number);
|
|
else
|
|
printf ("Incompatible ternary value '%c' in file '%s' line %lu\n",
|
|
(inex == 1) ? '+' : '-', pathname, test_line_number);
|
|
}
|
|
}
|
|
|
|
/* read lines of data */
|
|
static void
|
|
read_cc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpc_ptr op, mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpc (fp, op, NULL);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
static void
|
|
read_fc (FILE *fp, int *inex, mpfr_ptr expected, int *sign, mpc_ptr op,
|
|
mpfr_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex);
|
|
read_mpfr (fp, expected, sign);
|
|
read_mpc (fp, op, NULL);
|
|
read_mpfr_rounding_mode (fp, rnd);
|
|
check_compatible (*inex, expected, *rnd, NULL);
|
|
}
|
|
|
|
static void
|
|
read_ccc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpc_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpc (fp, op1, NULL);
|
|
read_mpc (fp, op2, NULL);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
/* read lines of data for function with three mpc_t inputs and one mpc_t
|
|
output like mpc_fma */
|
|
static void
|
|
read_cccc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpc_ptr op1, mpc_ptr op2, mpc_ptr op3,
|
|
mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpc (fp, op1, NULL);
|
|
read_mpc (fp, op2, NULL);
|
|
read_mpc (fp, op3, NULL);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
static void
|
|
read_cfc (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpfr_ptr op1, mpc_ptr op2, mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpfr (fp, op1, NULL);
|
|
read_mpc (fp, op2, NULL);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
static void
|
|
read_ccf (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpc_ptr op1, mpfr_ptr op2, mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpc (fp, op1, NULL);
|
|
read_mpfr (fp, op2, NULL);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
static void
|
|
read_ccu (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpc_ptr op1, unsigned long int *op2, mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpc (fp, op1, NULL);
|
|
read_uint (fp, op2);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
static void
|
|
read_ccs (FILE *fp, int *inex_re, int *inex_im, mpc_ptr expected,
|
|
known_signs_t *signs, mpc_ptr op1, long int *op2, mpc_rnd_t *rnd)
|
|
{
|
|
test_line_number = line_number;
|
|
read_ternary (fp, inex_re);
|
|
read_ternary (fp, inex_im);
|
|
read_mpc (fp, expected, signs);
|
|
read_mpc (fp, op1, NULL);
|
|
read_sint (fp, op2);
|
|
read_mpc_rounding_mode (fp, rnd);
|
|
check_compatible (*inex_re, mpc_realref(expected), MPC_RND_RE(*rnd), "real");
|
|
check_compatible (*inex_im, mpc_imagref(expected), MPC_RND_IM(*rnd), "imag");
|
|
}
|
|
|
|
/* set MPFR flags to random values */
|
|
static void
|
|
set_mpfr_flags (int counter)
|
|
{
|
|
if (counter & 1)
|
|
mpfr_set_underflow ();
|
|
else
|
|
mpfr_clear_underflow ();
|
|
if (counter & 2)
|
|
mpfr_set_overflow ();
|
|
else
|
|
mpfr_clear_overflow ();
|
|
/* the divide-by-0 flag was added in MPFR 3.1.0 */
|
|
#ifdef mpfr_set_divby0
|
|
if (counter & 4)
|
|
mpfr_set_divby0 ();
|
|
else
|
|
mpfr_clear_divby0 ();
|
|
#endif
|
|
if (counter & 8)
|
|
mpfr_set_nanflag ();
|
|
else
|
|
mpfr_clear_nanflag ();
|
|
if (counter & 16)
|
|
mpfr_set_inexflag ();
|
|
else
|
|
mpfr_clear_inexflag ();
|
|
if (counter & 32)
|
|
mpfr_set_erangeflag ();
|
|
else
|
|
mpfr_clear_erangeflag ();
|
|
}
|
|
|
|
/* Check MPFR flags: we allow that some flags are set internally by MPC,
|
|
for example if MPC does internal computations (using MPFR) which yield
|
|
an overflow, even if the final MPC result fits in the exponent range.
|
|
However we don't allow MPC to *clear* the MPFR flags */
|
|
static void
|
|
check_mpfr_flags (int counter)
|
|
{
|
|
int old, neu;
|
|
|
|
old = (counter & 1) != 0;
|
|
neu = mpfr_underflow_p () != 0;
|
|
if (old && (neu == 0))
|
|
{
|
|
printf ("Error, underflow flag has been modified from %d to %d\n",
|
|
old, neu);
|
|
exit (1);
|
|
}
|
|
old = (counter & 2) != 0;
|
|
neu = mpfr_overflow_p () != 0;
|
|
if (old && (neu == 0))
|
|
{
|
|
printf ("Error, overflow flag has been modified from %d to %d\n",
|
|
old, neu);
|
|
exit (1);
|
|
}
|
|
#ifdef mpfr_divby0_p
|
|
old = (counter & 4) != 0;
|
|
neu = mpfr_divby0_p () != 0;
|
|
if (old && (neu == 0))
|
|
{
|
|
printf ("Error, divby0 flag has been modified from %d to %d\n",
|
|
old, neu);
|
|
exit (1);
|
|
}
|
|
#endif
|
|
old = (counter & 8) != 0;
|
|
neu = mpfr_nanflag_p () != 0;
|
|
if (old && (neu == 0))
|
|
{
|
|
printf ("Error, nanflag flag has been modified from %d to %d\n",
|
|
old, neu);
|
|
exit (1);
|
|
}
|
|
old = (counter & 16) != 0;
|
|
neu = mpfr_inexflag_p () != 0;
|
|
if (old && (neu == 0))
|
|
{
|
|
printf ("Error, inexflag flag has been modified from %d to %d\n",
|
|
old, neu);
|
|
exit (1);
|
|
}
|
|
old = (counter & 32) != 0;
|
|
neu = mpfr_erangeflag_p () != 0;
|
|
if (old && (neu == 0))
|
|
{
|
|
printf ("Error, erangeflag flag has been modified from %d to %d\n",
|
|
old, neu);
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
/* data_check (function, data_file_name) checks function results against
|
|
precomputed data in a file.*/
|
|
void
|
|
data_check (mpc_function function, const char *file_name)
|
|
{
|
|
FILE *fp;
|
|
|
|
int inex_re;
|
|
mpfr_t x1, x2;
|
|
mpfr_rnd_t mpfr_rnd = GMP_RNDN;
|
|
int sign_real;
|
|
|
|
int inex_im;
|
|
mpc_t z1, z2, z3, z4, z5;
|
|
mpc_rnd_t rnd = MPC_RNDNN;
|
|
|
|
unsigned long int ui;
|
|
long int si;
|
|
|
|
known_signs_t signs;
|
|
int inex = 0;
|
|
|
|
static int rand_counter = 0;
|
|
|
|
fp = open_data_file (file_name);
|
|
|
|
/* 1. init needed variables */
|
|
mpc_init2 (z1, 2);
|
|
switch (function.type)
|
|
{
|
|
case FC:
|
|
mpfr_init (x1);
|
|
mpfr_init (x2);
|
|
break;
|
|
case CC: case CCU: case CCS:
|
|
mpc_init2 (z2, 2);
|
|
mpc_init2 (z3, 2);
|
|
break;
|
|
case C_CC:
|
|
mpc_init2 (z2, 2);
|
|
mpc_init2 (z3, 2);
|
|
mpc_init2 (z4, 2);
|
|
break;
|
|
case CCCC:
|
|
mpc_init2 (z2, 2);
|
|
mpc_init2 (z3, 2);
|
|
mpc_init2 (z4, 2);
|
|
mpc_init2 (z5, 2);
|
|
break;
|
|
case CFC: case CCF:
|
|
mpfr_init (x1);
|
|
mpc_init2 (z2, 2);
|
|
mpc_init2 (z3, 2);
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
/* 2. read data file */
|
|
line_number = 1;
|
|
nextchar = getc (fp);
|
|
skip_whitespace_comments (fp);
|
|
while (nextchar != EOF) {
|
|
set_mpfr_flags (rand_counter);
|
|
|
|
/* for each kind of function prototype: */
|
|
/* 3.1 read a line of data: expected result, parameters, rounding mode */
|
|
/* 3.2 compute function at the same precision as the expected result */
|
|
/* 3.3 compare this result with the expected one */
|
|
switch (function.type)
|
|
{
|
|
case FC: /* example mpc_norm */
|
|
read_fc (fp, &inex_re, x1, &sign_real, z1, &mpfr_rnd);
|
|
mpfr_set_prec (x2, mpfr_get_prec (x1));
|
|
inex = function.pointer.FC (x2, z1, mpfr_rnd);
|
|
if ((inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
|
|
|| !same_mpfr_value (x1, x2, sign_real))
|
|
{
|
|
mpfr_t got, expected;
|
|
mpc_t op;
|
|
op[0] = z1[0];
|
|
got[0] = x2[0];
|
|
expected[0] = x1[0];
|
|
printf ("%s(op) failed (%s:%lu)\nwith rounding mode %s\n",
|
|
function.name, file_name, test_line_number,
|
|
mpfr_rnd_mode[mpfr_rnd]);
|
|
if (inex_re != TERNARY_NOT_CHECKED && inex_re != inex)
|
|
printf("ternary value: got %s, expected %s\n",
|
|
MPFR_INEX_STR (inex), MPFR_INEX_STR (inex_re));
|
|
MPC_OUT (op);
|
|
printf (" ");
|
|
MPFR_OUT (got);
|
|
MPFR_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
break;
|
|
|
|
case CC: /* example mpc_log */
|
|
read_cc (fp, &inex_re, &inex_im, z1, &signs, z2, &rnd);
|
|
mpfr_set_prec (mpc_realref (z3), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref (z3), MPC_PREC_IM (z1));
|
|
inex = function.pointer.CC (z3, z2, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z3, z1, signs))
|
|
{
|
|
mpc_t op, got, expected; /* display sensible variable names */
|
|
op[0] = z2[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z3[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
break;
|
|
|
|
case C_CC: /* example mpc_mul */
|
|
read_ccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, &rnd);
|
|
mpfr_set_prec (mpc_realref(z4), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref(z4), MPC_PREC_IM (z1));
|
|
inex = function.pointer.C_CC (z4, z2, z3, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z4, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, op2, got, expected;
|
|
op1[0] = z2[0];
|
|
op2[0] = z3[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z4[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
MPC_OUT (op2);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
if (function.properties & FUNC_PROP_SYMETRIC)
|
|
{
|
|
inex = function.pointer.C_CC (z4, z3, z2, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z4, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, op2, got, expected;
|
|
op1[0] = z3[0];
|
|
op2[0] = z2[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z4[0];
|
|
printf ("%s(op) failed (line %lu/symetric test)\n"
|
|
"with rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
MPC_OUT (op2);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CCCC: /* example mpc_fma */
|
|
read_cccc (fp, &inex_re, &inex_im, z1, &signs, z2, z3, z4, &rnd);
|
|
/* z1 is the expected value, z2, z3, z4 are the inputs, and z5 is
|
|
the computed value */
|
|
mpfr_set_prec (mpc_realref(z5), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref(z5), MPC_PREC_IM (z1));
|
|
inex = function.pointer.CCCC (z5, z2, z3, z4, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z5, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, op2, op3, got, expected;
|
|
op1[0] = z2[0];
|
|
op2[0] = z3[0];
|
|
op3[0] = z4[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z5[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
MPC_OUT (op2);
|
|
MPC_OUT (op3);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
if (function.properties & FUNC_PROP_SYMETRIC)
|
|
{
|
|
inex = function.pointer.CCCC (z5, z3, z2, z4, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z5, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, op2, op3, got, expected;
|
|
op1[0] = z3[0];
|
|
op2[0] = z2[0];
|
|
op3[0] = z4[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z5[0];
|
|
printf ("%s(op) failed (line %lu/symetric test)\n"
|
|
"with rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
MPC_OUT (op2);
|
|
MPC_OUT (op3);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CFC: /* example mpc_fr_div */
|
|
read_cfc (fp, &inex_re, &inex_im, z1, &signs, x1, z2, &rnd);
|
|
mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
|
|
inex = function.pointer.CFC (z3, x1, z2, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z3, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op2, got, expected;
|
|
mpfr_t op1;
|
|
op1[0] = x1[0];
|
|
op2[0] = z2[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z3[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPFR_OUT (op1);
|
|
MPC_OUT (op2);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
break;
|
|
|
|
case CCF: /* example mpc_mul_fr */
|
|
read_ccf (fp, &inex_re, &inex_im, z1, &signs, z2, x1, &rnd);
|
|
mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
|
|
inex = function.pointer.CCF (z3, z2, x1, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z3, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, got, expected;
|
|
mpfr_t op2;
|
|
op1[0] = z2[0];
|
|
op2[0] = x1[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z3[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
MPFR_OUT (op2);
|
|
printf (" ");
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
break;
|
|
|
|
case CCU: /* example mpc_pow_ui */
|
|
read_ccu (fp, &inex_re, &inex_im, z1, &signs, z2, &ui, &rnd);
|
|
mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
|
|
inex = function.pointer.CCU (z3, z2, ui, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z3, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, got, expected;
|
|
op1[0] = z2[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z3[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
printf ("op2 %lu\n ", ui);
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
break;
|
|
|
|
case CCS: /* example mpc_pow_si */
|
|
read_ccs (fp, &inex_re, &inex_im, z1, &signs, z2, &si, &rnd);
|
|
mpfr_set_prec (mpc_realref(z3), MPC_PREC_RE (z1));
|
|
mpfr_set_prec (mpc_imagref(z3), MPC_PREC_IM (z1));
|
|
inex = function.pointer.CCS (z3, z2, si, rnd);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex)
|
|
|| !same_mpc_value (z3, z1, signs))
|
|
{
|
|
/* display sensible variable names */
|
|
mpc_t op1, got, expected;
|
|
op1[0] = z2[0];
|
|
expected[0]= z1[0];
|
|
got[0] = z3[0];
|
|
printf ("%s(op) failed (line %lu)\nwith rounding mode %s\n",
|
|
function.name, test_line_number, rnd_mode[rnd]);
|
|
if (!MPC_INEX_CMP (inex_re, inex_im, inex))
|
|
printf("ternary value: got %s, expected (%s, %s)\n",
|
|
MPC_INEX_STR (inex),
|
|
MPFR_INEX_STR (inex_re), MPFR_INEX_STR (inex_im));
|
|
MPC_OUT (op1);
|
|
printf ("op2 %li\n ", si);
|
|
MPC_OUT (got);
|
|
MPC_OUT (expected);
|
|
|
|
exit (1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf ("Unhandled function prototype %i in 'data_check'\n", function.type);
|
|
exit (1);
|
|
}
|
|
|
|
/* check MPFR flags were not modified */
|
|
check_mpfr_flags (rand_counter);
|
|
rand_counter ++;
|
|
}
|
|
|
|
/* 3. Clear used variables */
|
|
mpc_clear (z1);
|
|
switch (function.type)
|
|
{
|
|
case FC:
|
|
mpfr_clear (x1);
|
|
mpfr_clear (x2);
|
|
break;
|
|
case CC: case CCU: case CCS:
|
|
mpc_clear (z2);
|
|
mpc_clear (z3);
|
|
break;
|
|
case C_CC:
|
|
mpc_clear (z2);
|
|
mpc_clear (z3);
|
|
mpc_clear (z4);
|
|
break;
|
|
case CCCC:
|
|
mpc_clear (z2);
|
|
mpc_clear (z3);
|
|
mpc_clear (z4);
|
|
mpc_clear (z5);
|
|
break;
|
|
case CFC: case CCF:
|
|
mpfr_clear (x1);
|
|
mpc_clear (z2);
|
|
mpc_clear (z3);
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
close_data_file (fp);
|
|
}
|