1/* rounding.c -- file for functions iterating over rounding modes.
2
3Copyright (C) 2013, 2014, 2022 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 "mpc-tests.h"
22
23/* helper functions for iterating over mpfr rounding modes */
24
25#define FIRST_MPFR_RND_MODE MPFR_RNDN
26
27static mpfr_rnd_t
28next_mpfr_rnd_mode (mpfr_rnd_t curr)
29{
30  switch (curr)
31    {
32    case MPFR_RNDN:
33      return MPFR_RNDZ;
34    case MPFR_RNDZ:
35      return MPFR_RNDU;
36    case MPFR_RNDU:
37      return MPFR_RNDD;
38    case MPFR_RNDD:
39      return MPFR_RNDA;
40    default:
41      /* return invalid guard value in mpfr_rnd_t */
42      return MPFR_RNDNA;
43    }
44}
45
46static int
47is_valid_mpfr_rnd_mode (mpfr_rnd_t curr)
48/* returns 1 if curr is a valid rounding mode, and 0 otherwise */
49{
50   if (   curr == MPFR_RNDN || curr == MPFR_RNDZ
51       || curr == MPFR_RNDU || curr == MPFR_RNDD
52       || curr == MPFR_RNDA)
53      return 1;
54   else
55      return 0;
56}
57
58static mpc_rnd_t
59next_mpc_rnd_mode (mpc_rnd_t rnd)
60{
61  mpfr_rnd_t rnd_re = MPC_RND_RE (rnd);
62  mpfr_rnd_t rnd_im = MPC_RND_IM (rnd);
63
64  rnd_im = next_mpfr_rnd_mode (rnd_im);
65  if (!is_valid_mpfr_rnd_mode (rnd_im))
66    {
67      rnd_re = next_mpfr_rnd_mode (rnd_re);
68      rnd_im = FIRST_MPFR_RND_MODE;
69    }
70
71  return MPC_RND(rnd_re, rnd_im);
72}
73
74static int
75is_valid_mpc_rnd_mode (mpc_rnd_t rnd)
76/* returns 1 if curr is a valid rounding mode, and 0 otherwise */
77{
78  mpfr_rnd_t rnd_re = MPC_RND_RE (rnd);
79  mpfr_rnd_t rnd_im = MPC_RND_IM (rnd);
80
81  return is_valid_mpfr_rnd_mode (rnd_re) && is_valid_mpfr_rnd_mode (rnd_im);
82}
83
84/* functions using abstract parameters */
85
86static void
87first_mode (mpc_fun_param_t *params, int index)
88{
89  switch (params->T[index])
90    {
91    case MPC_RND:
92      params->P[index].mpc_rnd =
93        MPC_RND(FIRST_MPFR_RND_MODE, FIRST_MPFR_RND_MODE);
94      break;
95    case MPFR_RND:
96      params->P[index].mpfr_rnd = FIRST_MPFR_RND_MODE;
97      break;
98    default:
99      printf ("The rounding mode is expected to be"
100              " the last input parameter.\n");
101      exit (-1);
102    }
103}
104
105static void
106next_mode (mpc_fun_param_t *params, int index)
107{
108  switch (params->T[index])
109    {
110    case MPC_RND:
111      params->P[index].mpc_rnd =
112        next_mpc_rnd_mode (params->P[index].mpc_rnd);
113      break;
114    case MPFR_RND:
115      params->P[index].mpfr_rnd =
116        next_mpfr_rnd_mode (params->P[index].mpfr_rnd);
117      break;
118    default:
119      printf ("The rounding mode is expected to be"
120              " the last input parameter.\n");
121      exit (-1);
122    }
123}
124
125static int
126is_valid_mode (mpc_fun_param_t *params, int index)
127/* returns 1 if params->P[index] is a valid rounding mode, and 0 otherwise */
128{
129  switch (params->T[index])
130    {
131    case MPC_RND:
132      return is_valid_mpc_rnd_mode (params->P[index].mpc_rnd);
133    case MPFR_RND:
134      return is_valid_mpfr_rnd_mode (params->P[index].mpfr_rnd);
135    default:
136      printf ("The rounding mode is expected to be"
137              " the last input parameter.\n");
138      exit (-1);
139    }
140}
141
142void
143first_rnd_mode (mpc_fun_param_t *params)
144{
145  int rnd_mode_index;
146
147  for (rnd_mode_index = params->nbout + params->nbin - params->nbrnd;
148       rnd_mode_index < params->nbout + params->nbin;
149       rnd_mode_index++)
150    {
151      first_mode (params, rnd_mode_index);
152    }
153}
154
155
156void
157next_rnd_mode (mpc_fun_param_t *params)
158/* cycle through all valid rounding modes and finish with an invalid one */
159{
160  int last = params->nbout + params->nbin - 1;
161  int index = params->nbout + params->nbin - params->nbrnd;
162  int carry = 1;
163
164  while (carry && index <= last) {
165    next_mode (params, index);
166    if (!is_valid_mode (params, index) && index < last)
167      first_mode (params, index);
168    else
169      carry = 0;
170    index++;
171  }
172}
173
174int
175is_valid_rnd_mode (mpc_fun_param_t *params)
176/* returns 1 if all rounding parameters are set to a valid rounding mode,
177   and 0 otherwise */
178{
179  int index;
180
181  for (index = params->nbout + params->nbin - params->nbrnd;
182       index < params->nbout + params->nbin;
183       index++)
184    if (! is_valid_mode (params, index))
185      return 0;
186
187  return 1;
188}
189