1 /* rounding.c -- file for functions iterating over rounding modes.
2
3 Copyright (C) 2013, 2014, 2022 INRIA
4
5 This file is part of GNU MPC.
6
7 GNU MPC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along 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
27 static mpfr_rnd_t
next_mpfr_rnd_mode(mpfr_rnd_t curr)28 next_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
46 static int
is_valid_mpfr_rnd_mode(mpfr_rnd_t curr)47 is_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
58 static mpc_rnd_t
next_mpc_rnd_mode(mpc_rnd_t rnd)59 next_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
74 static int
is_valid_mpc_rnd_mode(mpc_rnd_t rnd)75 is_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
86 static void
first_mode(mpc_fun_param_t * params,int index)87 first_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
105 static void
next_mode(mpc_fun_param_t * params,int index)106 next_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
125 static int
is_valid_mode(mpc_fun_param_t * params,int index)126 is_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
142 void
first_rnd_mode(mpc_fun_param_t * params)143 first_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
156 void
next_rnd_mode(mpc_fun_param_t * params)157 next_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
174 int
is_valid_rnd_mode(mpc_fun_param_t * params)175 is_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