mirror of
https://review.haiku-os.org/buildtools
synced 2025-02-14 17:57:39 +01:00
190 lines
4.6 KiB
C
190 lines
4.6 KiB
C
/* rounding.c -- file for functions iterating over rounding modes.
|
|
|
|
Copyright (C) 2013, 2014 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 "mpc-tests.h"
|
|
|
|
/* helper functions for iterating over mpfr rounding modes */
|
|
|
|
#define FIRST_MPFR_RND_MODE MPFR_RNDN
|
|
|
|
static mpfr_rnd_t
|
|
next_mpfr_rnd_mode (mpfr_rnd_t curr)
|
|
{
|
|
switch (curr)
|
|
{
|
|
case MPFR_RNDN:
|
|
return MPFR_RNDZ;
|
|
case MPFR_RNDZ:
|
|
return MPFR_RNDU;
|
|
case MPFR_RNDU:
|
|
return MPFR_RNDD;
|
|
default:
|
|
/* return invalid guard value in mpfr_rnd_t */
|
|
#if MPFR_VERSION_MAJOR < 3
|
|
return MPFR_RNDNA;
|
|
#else
|
|
return MPFR_RNDA; /* valid rounding type, but not used in mpc */
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static int
|
|
is_valid_mpfr_rnd_mode (mpfr_rnd_t curr)
|
|
/* returns 1 if curr is a valid rounding mode, and 0 otherwise */
|
|
{
|
|
if ( curr == MPFR_RNDN || curr == MPFR_RNDZ
|
|
|| curr == MPFR_RNDU || curr == MPFR_RNDD)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static mpc_rnd_t
|
|
next_mpc_rnd_mode (mpc_rnd_t rnd)
|
|
{
|
|
mpfr_rnd_t rnd_re = MPC_RND_RE (rnd);
|
|
mpfr_rnd_t rnd_im = MPC_RND_IM (rnd);
|
|
|
|
rnd_im = next_mpfr_rnd_mode (rnd_im);
|
|
if (!is_valid_mpfr_rnd_mode (rnd_im))
|
|
{
|
|
rnd_re = next_mpfr_rnd_mode (rnd_re);
|
|
rnd_im = FIRST_MPFR_RND_MODE;
|
|
}
|
|
|
|
return MPC_RND(rnd_re, rnd_im);
|
|
}
|
|
|
|
static int
|
|
is_valid_mpc_rnd_mode (mpc_rnd_t rnd)
|
|
/* returns 1 if curr is a valid rounding mode, and 0 otherwise */
|
|
{
|
|
mpfr_rnd_t rnd_re = MPC_RND_RE (rnd);
|
|
mpfr_rnd_t rnd_im = MPC_RND_IM (rnd);
|
|
|
|
return is_valid_mpfr_rnd_mode (rnd_re) && is_valid_mpfr_rnd_mode (rnd_im);
|
|
}
|
|
|
|
/* functions using abstract parameters */
|
|
|
|
static void
|
|
first_mode (mpc_fun_param_t *params, int index)
|
|
{
|
|
switch (params->T[index])
|
|
{
|
|
case MPC_RND:
|
|
params->P[index].mpc_rnd =
|
|
MPC_RND(FIRST_MPFR_RND_MODE, FIRST_MPFR_RND_MODE);
|
|
break;
|
|
case MPFR_RND:
|
|
params->P[index].mpfr_rnd = FIRST_MPFR_RND_MODE;
|
|
break;
|
|
default:
|
|
printf ("The rounding mode is expected to be"
|
|
" the last input parameter.\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
next_mode (mpc_fun_param_t *params, int index)
|
|
{
|
|
switch (params->T[index])
|
|
{
|
|
case MPC_RND:
|
|
params->P[index].mpc_rnd =
|
|
next_mpc_rnd_mode (params->P[index].mpc_rnd);
|
|
break;
|
|
case MPFR_RND:
|
|
params->P[index].mpfr_rnd =
|
|
next_mpfr_rnd_mode (params->P[index].mpfr_rnd);
|
|
break;
|
|
default:
|
|
printf ("The rounding mode is expected to be"
|
|
" the last input parameter.\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
static int
|
|
is_valid_mode (mpc_fun_param_t *params, int index)
|
|
/* returns 1 if params->P[index] is a valid rounding mode, and 0 otherwise */
|
|
{
|
|
switch (params->T[index])
|
|
{
|
|
case MPC_RND:
|
|
return is_valid_mpc_rnd_mode (params->P[index].mpc_rnd);
|
|
case MPFR_RND:
|
|
return is_valid_mpfr_rnd_mode (params->P[index].mpfr_rnd);
|
|
default:
|
|
printf ("The rounding mode is expected to be"
|
|
" the last input parameter.\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
void
|
|
first_rnd_mode (mpc_fun_param_t *params)
|
|
{
|
|
int rnd_mode_index;
|
|
|
|
for (rnd_mode_index = params->nbout + params->nbin - params->nbrnd;
|
|
rnd_mode_index < params->nbout + params->nbin;
|
|
rnd_mode_index++)
|
|
{
|
|
first_mode (params, rnd_mode_index);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
next_rnd_mode (mpc_fun_param_t *params)
|
|
/* cycle through all valid rounding modes and finish with an invalid one */
|
|
{
|
|
int last = params->nbout + params->nbin - 1;
|
|
int index = params->nbout + params->nbin - params->nbrnd;
|
|
int carry = 1;
|
|
|
|
while (carry && index <= last) {
|
|
next_mode (params, index);
|
|
if (!is_valid_mode (params, index) && index < last)
|
|
first_mode (params, index);
|
|
else
|
|
carry = 0;
|
|
index++;
|
|
}
|
|
}
|
|
|
|
int
|
|
is_valid_rnd_mode (mpc_fun_param_t *params)
|
|
/* returns 1 if all rounding parameters are set to a valid rounding mode,
|
|
and 0 otherwise */
|
|
{
|
|
int index;
|
|
|
|
for (index = params->nbout + params->nbin - params->nbrnd;
|
|
index < params->nbout + params->nbin;
|
|
index++)
|
|
if (! is_valid_mode (params, index))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|