xref: /netbsd-src/external/lgpl3/mpc/dist/tests/rounding.c (revision 367b82799ab709709d3c3b541df56a2a14644d3e)
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