1/* tgeneric.tpl -- template file for generic tests. 2 3Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 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#ifndef MPC_FUNCTION_CALL 22#error Define MPC_FUNCTION_CALL before including 'data_check.tpl'. 23#endif 24 25/* helper functions, defined after tgeneric */ 26static int count_special_cases (mpc_fun_param_t *params); 27static void random_params (mpc_fun_param_t *params, 28 mpfr_exp_t exp_min, mpfr_exp_t exp_max, 29 int special); 30static void check_against_quadruple_precision (mpc_fun_param_t *params, 31 mpfr_prec_t prec, 32 mpfr_exp_t exp_min, 33 mpfr_exp_t exp_max, 34 int special); 35 36 37/* tgeneric(desc, prec_min, prec_max, step, exp_max) checks rounding with 38 random numbers: 39 - with precision ranging from prec_min to prec_max with an increment of 40 step, 41 - with exponent between -exp_max and exp_max. 42 - for pure real, pure imaginary and infinite random parameters. 43 44 It also checks parameter reuse. 45*/ 46static void 47tgeneric_template (const char *description_file, 48 mpfr_prec_t prec_min, mpfr_prec_t prec_max, mpfr_prec_t step, 49 mpfr_exp_t exp_max) 50{ 51 int special = 0; 52 int last_special; 53 mpfr_prec_t prec; 54 mpfr_exp_t exp_min; 55 mpc_fun_param_t params; 56 57 read_description (¶ms, description_file); 58 init_parameters (¶ms); 59 60 /* ask for enough memory */ 61 set_output_precision (¶ms, 4 * prec_max); 62 set_input_precision (¶ms, prec_max); 63 set_reference_precision (¶ms, prec_max); 64 65 /* sanity checks */ 66 exp_min = mpfr_get_emin (); 67 if (exp_max <= 0 || exp_max > mpfr_get_emax ()) 68 exp_max = mpfr_get_emax(); 69 if (-exp_max > exp_min) 70 exp_min = - exp_max; 71 if (step < 1) 72 step = 1; 73 74 /* check consistency with quadruple precision for random parameters */ 75 for (prec = prec_min; prec <= prec_max; prec += step) 76 check_against_quadruple_precision (¶ms, prec, exp_min, exp_max, -1); 77 78 /* check consistency with quadruple precision for special values: 79 pure real, pure imaginary, or infinite arguments */ 80 last_special = count_special_cases (¶ms); 81 for (special = 0; special < last_special ; special++) 82 check_against_quadruple_precision (¶ms, prec_max, exp_min, exp_max, 83 special); 84 85 clear_parameters (¶ms); 86} 87 88 89static void 90check_against_quadruple_precision (mpc_fun_param_t *params, 91 mpfr_prec_t prec, 92 mpfr_exp_t exp_min, mpfr_exp_t exp_max, 93 int special) 94{ 95 static int rand_counter = 0; 96 mpc_operand_t *P = params->P; /* developer-friendly alias, used in macros */ 97 98 set_input_precision (params, prec); 99 set_reference_precision (params, prec); 100 101 set_output_precision (params, 4 * prec); 102 random_params (params, exp_min, exp_max, special); 103 104 for (first_rnd_mode (params); 105 is_valid_rnd_mode (params); 106 next_rnd_mode (params)) 107 { 108 MPC_FUNCTION_CALL; 109 while (double_rounding (params)) 110 /* try another input parameters until no double rounding occurs when 111 the extra-precise result is rounded to working precision */ 112 { 113 random_params (params, exp_min, exp_max, special); 114 MPC_FUNCTION_CALL; 115 } 116 set_output_precision (params, prec); 117 118 set_mpfr_flags (rand_counter); 119 MPC_FUNCTION_CALL; 120 check_mpfr_flags (rand_counter++); 121 check_data (NULL, params, 0); 122 123#ifdef MPC_FUNCTION_CALL_SYMMETRIC 124 MPC_FUNCTION_CALL_SYMMETRIC; 125 check_data (NULL, params, 0); 126#endif 127 128#ifdef MPC_FUNCTION_CALL_REUSE_OP1 129 if (copy_parameter (params, 1, 2) == 0) 130 { 131 MPC_FUNCTION_CALL_REUSE_OP1; 132 check_data (NULL, params, 2); 133 } 134#endif 135 136#ifdef MPC_FUNCTION_CALL_REUSE_OP2 137 if (copy_parameter (params, 1, 3) == 0) 138 { 139 MPC_FUNCTION_CALL_REUSE_OP2; 140 check_data (NULL, params, 3); 141 } 142#endif 143 144#ifdef MPC_FUNCTION_CALL_REUSE_OP3 145 if (copy_parameter (params, 1, 4) == 0) 146 { 147 MPC_FUNCTION_CALL_REUSE_OP3; 148 check_data (NULL, params, 4); 149 } 150#endif 151 152 set_output_precision (params, 4 * prec); 153 } 154} 155 156 157/* special cases */ 158 159enum { 160 SPECIAL_MINF, 161 SPECIAL_MZERO, 162 SPECIAL_PZERO, 163 SPECIAL_PINF, 164 SPECIAL_COUNT 165}; 166 167static int 168count_special_cases (mpc_fun_param_t *params) 169/* counts the number of possibilities of exactly one real or imaginary part of 170 any input parameter being special, all others being finite real numbers */ 171{ 172 int i; 173 const int start = params->nbout; 174 const int end = start + params->nbin - 1; /* the last input parameter is the 175 rounding mode */ 176 int count = 0; 177 178 for (i = start; i < end; i++) 179 { 180 if (params->T[i] == MPFR) 181 count += SPECIAL_COUNT; 182 else if (params->T[i] == MPC) 183 /* special + i x random and random + i x special */ 184 count += 2 * SPECIAL_COUNT; 185 } 186 return count; 187} 188 189static void 190special_mpfr (mpfr_ptr x, int special) 191{ 192 switch (special) 193 { 194 case SPECIAL_MINF: 195 mpfr_set_inf (x, -1); 196 break; 197 case SPECIAL_MZERO: 198 mpfr_set_zero (x, -1); 199 break; 200 case SPECIAL_PZERO: 201 mpfr_set_zero (x, +1); 202 break; 203 case SPECIAL_PINF: 204 mpfr_set_inf (x, +1); 205 break; 206 case SPECIAL_COUNT: 207 /* does not occur */ 208 break; 209 } 210} 211 212static void 213special_random_mpc (mpc_ptr z, mpfr_exp_t exp_min, mpfr_exp_t exp_max, 214 int special) 215{ 216 mpfr_ptr special_part; 217 mpfr_ptr random_part; 218 int mpfr_special; 219 220 if (special < SPECIAL_COUNT) 221 { 222 mpfr_special = special; 223 special_part = mpc_realref (z); 224 random_part = mpc_imagref (z); 225 } 226 else 227 { 228 mpfr_special = special - SPECIAL_COUNT; 229 special_part = mpc_imagref (z); 230 random_part = mpc_realref (z); 231 } 232 233 special_mpfr (special_part, mpfr_special); 234 test_random_mpfr (random_part, exp_min, exp_max, 128); 235} 236 237static void 238random_params (mpc_fun_param_t *params, 239 mpfr_exp_t exp_min, mpfr_exp_t exp_max, 240 int special) 241{ 242 int i; 243 int base_index = 0; 244 const int start = params->nbout; 245 const int end = start + params->nbin; 246 const unsigned int int_emax = 42; /* maximum binary exponent for random 247 integer */ 248 249 for (i = start; i < end; i++) 250 { 251 long int si; 252 switch (params->T[i]) 253 { 254 case NATIVE_INT: 255 test_random_si (&si, int_emax, 128); 256 params->P[i].i = (int) si; 257 break; 258 case NATIVE_L: 259 test_random_si (¶ms->P[i].si, int_emax, 128); 260 break; 261 case NATIVE_UL: 262 test_random_si (&si, int_emax, 128); 263 params->P[i].ui = (unsigned long)si; 264 break; 265 266 case NATIVE_D: 267 test_random_d (¶ms->P[i].d, 128); 268 break; 269 270 case NATIVE_LD: 271 case NATIVE_DC: 272 case NATIVE_LDC: 273 /* TODO: draw random value */ 274 fprintf (stderr, "random_params: type not implemented.\n"); 275 exit (1); 276 break; 277 278 case NATIVE_IM: 279 case NATIVE_UIM: 280 /* TODO: draw random value */ 281 fprintf (stderr, "random_params: type not implemented.\n"); 282 exit (1); 283 break; 284 285 case GMP_Z: 286 /* TODO: draw random value */ 287 fprintf (stderr, "random_params: type not implemented.\n"); 288 exit (1); 289 break; 290 case GMP_Q: 291 /* TODO: draw random value */ 292 fprintf (stderr, "random_params: type not implemented.\n"); 293 exit (1); 294 break; 295 case GMP_F: 296 /* TODO: draw random value */ 297 fprintf (stderr, "random_params: type not implemented.\n"); 298 exit (1); 299 break; 300 301 case MPFR: 302 if (base_index <= special 303 && special - base_index < SPECIAL_COUNT) 304 special_mpfr (params->P[i].mpfr, special - base_index); 305 else 306 test_random_mpfr (params->P[i].mpfr, exp_min, exp_max, 128); 307 base_index += SPECIAL_COUNT; 308 break; 309 310 case MPC: 311 if (base_index <= special 312 && special - base_index < 2 * SPECIAL_COUNT) 313 special_random_mpc (params->P[i].mpc, exp_min, exp_max, 314 special - base_index); 315 else 316 test_random_mpc (params->P[i].mpc, exp_min, exp_max, 128); 317 base_index += 2 * SPECIAL_COUNT; 318 break; 319 320 case NATIVE_STRING: 321 case MPFR_INEX: 322 case MPC_INEX: 323 case MPCC_INEX: 324 /* unsupported types */ 325 fprintf (stderr, "random_params: unsupported type.\n"); 326 exit (1); 327 break; 328 329 case MPFR_RND: 330 case MPC_RND: 331 /* just skip rounding mode(s) */ 332 break; 333 } 334 } 335} 336