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