/* [Description] Copyright 2010-2019 Free Software Foundation, Inc. Contributed by the AriC and Caramba projects, INRIA. This file is part of the GNU MPFR Library. The GNU MPFR Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU MPFR Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #define MPFR_NEED_LONGLONG_H #include "mpfr-impl.h" #undef _PROTO #define _PROTO __GMP_PROTO #include "speed.h" /* Let f be a function for which we have several implementations f1, f2... */ /* We wish to have a quick overview of which implementation is the best */ /* in function of the point x where f(x) is computed and of the precision */ /* prec requested by the user. */ /* This is performed by drawing a 2D graphic with color indicating which */ /* method is the best. */ /* For building this graphic, the following structur is used (see the core */ /* of generate_2D_sample for an explanation of each field. */ struct speed_params2D { /* x-window: [min_x, max_x] or [2^min_x, 2^max_x] */ /* or [-2^(max_x), -2^(min_x)] U [2^min_x, 2^max_x] */ /* depending on the value of logarithmic_scale_x */ double min_x; double max_x; /* prec-window: [min_prec, max_prec] */ mpfr_prec_t min_prec; mpfr_prec_t max_prec; /* number of sample points for the x-axis and the prec-axis */ int nb_points_x; int nb_points_prec; /* should the sample points be logarithmically scaled or not */ int logarithmic_scale_x; int logarithmic_scale_prec; /* list of functions g1, g2... measuring the execution time of f1, f2... */ /* when given a point x and a precision prec stored in s. */ /* We use s->xp to store the significant of x, s->r to store its exponent */ /* s->align_xp to store its sign, and s->size to store prec. */ double (**speed_funcs) (struct speed_params *s); }; /* Given an array t of nb_functions double indicating the timings of several */ /* implementations, return i, such that t[i] is the best timing. */ int find_best (double *t, int nb_functions) { int i, ibest; double best; if (nb_functions<=0) { fprintf (stderr, "There is no function\n"); abort (); } ibest = 0; best = t[0]; for (i=1; i 0)?1:2; mpfr_set_prec (x2, (mpfr_prec_t)prec); mpfr_set (x2, x, MPFR_RNDU); s.xp = x2->_mpfr_d; for (i=0; i 0) test=0; } else { if (mpfr_sgn (x) < 0 ) { /* if x<0, it means that logarithmic_scale_x=-1 */ mpfr_div (x, x, incr_x, MPFR_RNDU); mpfr_abs (temp, x, MPFR_RNDD); mpfr_log2 (temp, temp, MPFR_RNDD); if (mpfr_cmp_d (temp, param.min_x) < 0) mpfr_neg (x, x, MPFR_RNDN); } else { mpfr_mul (x, x, incr_x, MPFR_RNDU); mpfr_set (temp, x, MPFR_RNDD); mpfr_log2 (temp, temp, MPFR_RNDD); if (mpfr_cmp_d (temp, param.max_x) > 0) test=0; } } } prec = ( (param.logarithmic_scale_prec) ? (prec * incr_prec) : (prec + incr_prec) ); fprintf (output, "\n"); } free (t); mpfr_clear (incr_x); mpfr_clear (x); mpfr_clear (x2); mpfr_clear (temp); return; } #define SPEED_MPFR_FUNC_2D(mean_func) \ do \ { \ double t; \ unsigned i; \ mpfr_t w, x; \ mp_size_t size; \ \ SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ \ size = (s->size-1)/GMP_NUMB_BITS+1; \ s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ MPFR_TMP_INIT1 (s->xp, x, s->size); \ MPFR_SET_EXP (x, (mpfr_exp_t) s->r); \ if (s->align_xp == 2) MPFR_SET_NEG (x); \ \ mpfr_init2 (w, s->size); \ speed_starttime (); \ i = s->reps; \ \ do \ mean_func (w, x, MPFR_RNDN); \ while (--i != 0); \ t = speed_endtime (); \ \ mpfr_clear (w); \ return t; \ } \ while (0) mpfr_prec_t mpfr_exp_2_threshold; mpfr_prec_t old_threshold = MPFR_EXP_2_THRESHOLD; #undef MPFR_EXP_2_THRESHOLD #define MPFR_EXP_2_THRESHOLD mpfr_exp_2_threshold #include "exp_2.c" double timing_exp1 (struct speed_params *s) { mpfr_exp_2_threshold = s->size+1; SPEED_MPFR_FUNC_2D (mpfr_exp_2); } double timing_exp2 (struct speed_params *s) { mpfr_exp_2_threshold = s->size-1; SPEED_MPFR_FUNC_2D (mpfr_exp_2); } double timing_exp3 (struct speed_params *s) { SPEED_MPFR_FUNC_2D (mpfr_exp_3); } #include "ai.c" double timing_ai1 (struct speed_params *s) { SPEED_MPFR_FUNC_2D (mpfr_ai1); } double timing_ai2 (struct speed_params *s) { SPEED_MPFR_FUNC_2D (mpfr_ai2); } /* These functions are for testing purpose only */ /* They are used to draw which method is actually used */ double virtual_timing_ai1 (struct speed_params *s) { double t; unsigned i; mpfr_t w, x; mp_size_t size; mpfr_t temp1, temp2; SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); size = (s->size-1)/GMP_NUMB_BITS+1; s->xp[size-1] |= MPFR_LIMB_HIGHBIT; MPFR_TMP_INIT1 (s->xp, x, s->size); MPFR_SET_EXP (x, (mpfr_exp_t) s->r); if (s->align_xp == 2) MPFR_SET_NEG (x); mpfr_init2 (w, s->size); speed_starttime (); i = s->reps; mpfr_init2 (temp1, MPFR_SMALL_PRECISION); mpfr_init2 (temp2, MPFR_SMALL_PRECISION); mpfr_set (temp1, x, MPFR_SMALL_PRECISION); mpfr_set_si (temp2, MPFR_AI_THRESHOLD2, MPFR_RNDN); mpfr_mul_ui (temp2, temp2, (unsigned int)MPFR_PREC (w), MPFR_RNDN); if (MPFR_IS_NEG (x)) mpfr_mul_si (temp1, temp1, MPFR_AI_THRESHOLD1, MPFR_RNDN); else mpfr_mul_si (temp1, temp1, MPFR_AI_THRESHOLD3, MPFR_RNDN); mpfr_add (temp1, temp1, temp2, MPFR_RNDN); if (mpfr_cmp_si (temp1, MPFR_AI_SCALE) > 0) t = 1000.; else t = 1.; mpfr_clear (temp1); mpfr_clear (temp2); return t; } double virtual_timing_ai2 (struct speed_params *s) { double t; unsigned i; mpfr_t w, x; mp_size_t size; mpfr_t temp1, temp2; SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); size = (s->size-1)/GMP_NUMB_BITS+1; s->xp[size-1] |= MPFR_LIMB_HIGHBIT; MPFR_TMP_INIT1 (s->xp, x, s->size); MPFR_SET_EXP (x, (mpfr_exp_t) s->r); if (s->align_xp == 2) MPFR_SET_NEG (x); mpfr_init2 (w, s->size); speed_starttime (); i = s->reps; mpfr_init2 (temp1, MPFR_SMALL_PRECISION); mpfr_init2 (temp2, MPFR_SMALL_PRECISION); mpfr_set (temp1, x, MPFR_SMALL_PRECISION); mpfr_set_si (temp2, MPFR_AI_THRESHOLD2, MPFR_RNDN); mpfr_mul_ui (temp2, temp2, (unsigned int)MPFR_PREC (w), MPFR_RNDN); if (MPFR_IS_NEG (x)) mpfr_mul_si (temp1, temp1, MPFR_AI_THRESHOLD1, MPFR_RNDN); else mpfr_mul_si (temp1, temp1, MPFR_AI_THRESHOLD3, MPFR_RNDN); mpfr_add (temp1, temp1, temp2, MPFR_RNDN); if (mpfr_cmp_si (temp1, MPFR_AI_SCALE) > 0) t = 1.; else t = 1000.; mpfr_clear (temp1); mpfr_clear (temp2); return t; } int main (void) { FILE *output; struct speed_params2D param; double (*speed_funcs[3]) (struct speed_params *s); /* char filename[256] = "virtual_timing_ai.dat"; */ /* speed_funcs[0] = virtual_timing_ai1; */ /* speed_funcs[1] = virtual_timing_ai2; */ char filename[256] = "airy.dat"; speed_funcs[0] = timing_ai1; speed_funcs[1] = timing_ai2; speed_funcs[2] = NULL; output = fopen (filename, "w"); if (output == NULL) { fprintf (stderr, "Can't open file '%s' for writing.\n", filename); abort (); } param.min_x = -80; param.max_x = 60; param.min_prec = 50; param.max_prec = 1500; param.nb_points_x = 200; param.nb_points_prec = 200; param.logarithmic_scale_x = 0; param.logarithmic_scale_prec = 0; param.speed_funcs = speed_funcs; generate_2D_sample (output, param); fclose (output); mpfr_free_cache (); return 0; }