Home | History | Annotate | Line # | Download | only in tests
      1 /* tgeneric.tpl -- template file for generic tests.
      2 
      3 Copyright (C) 2008, 2009, 2010, 2011, 2012, 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 #ifndef MPC_FUNCTION_CALL
     22 #error Define MPC_FUNCTION_CALL before including 'data_check.tpl'.
     23 #endif
     24 
     25 /* helper functions, defined after tgeneric */
     26 static int  count_special_cases  (mpc_fun_param_t *params);
     27 static void random_params        (mpc_fun_param_t *params,
     28                                   mpfr_exp_t exp_min, mpfr_exp_t exp_max,
     29                                   int special);
     30 static 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 */
     46 static void
     47 tgeneric_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 (&params, description_file);
     58   init_parameters (&params);
     59 
     60   /* ask for enough memory */
     61   set_output_precision (&params, 4 * prec_max);
     62   set_input_precision (&params, prec_max);
     63   set_reference_precision (&params, 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 (&params, 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 (&params);
     81   for (special = 0; special < last_special ; special++)
     82     check_against_quadruple_precision (&params, prec_max, exp_min, exp_max,
     83                                        special);
     84 
     85   clear_parameters (&params);
     86 }
     87 
     88 
     89 static void
     90 check_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 
    159 enum {
    160   SPECIAL_MINF,
    161   SPECIAL_MZERO,
    162   SPECIAL_PZERO,
    163   SPECIAL_PINF,
    164   SPECIAL_COUNT
    165 };
    166 
    167 static int
    168 count_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 
    189 static void
    190 special_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 
    212 static void
    213 special_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 
    237 static void
    238 random_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 (&params->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 (&params->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