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