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