github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tune/tune-gcd-p.c (about)

     1  /* tune-gcd-p
     2  
     3     Tune the choice for splitting p in divide-and-conquer gcd.
     4  
     5  Copyright 2008, 2010, 2011 Free Software Foundation, Inc.
     6  
     7  This file is part of the GNU MP Library.
     8  
     9  The GNU MP Library is free software; you can redistribute it and/or modify
    10  it under the terms of either:
    11  
    12    * the GNU Lesser General Public License as published by the Free
    13      Software Foundation; either version 3 of the License, or (at your
    14      option) any later version.
    15  
    16  or
    17  
    18    * the GNU General Public License as published by the Free Software
    19      Foundation; either version 2 of the License, or (at your option) any
    20      later version.
    21  
    22  or both in parallel, as here.
    23  
    24  The GNU MP Library is distributed in the hope that it will be useful, but
    25  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    26  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    27  for more details.
    28  
    29  You should have received copies of the GNU General Public License and the
    30  GNU Lesser General Public License along with the GNU MP Library.  If not,
    31  see https://www.gnu.org/licenses/.  */
    32  
    33  #define TUNE_GCD_P 1
    34  
    35  #include "../mpn/gcd.c"
    36  
    37  #include <stdio.h>
    38  #include <stdlib.h>
    39  #include <string.h>
    40  #include <time.h>
    41  
    42  #include "speed.h"
    43  
    44  /* Search for minimum over a range. FIXME: Implement golden-section /
    45     fibonacci search*/
    46  static int
    47  search (double *minp, double (*f)(void *, int), void *ctx, int start, int end)
    48  {
    49    int x[4];
    50    double y[4];
    51  
    52    int best_i;
    53  
    54    x[0] = start;
    55    x[3] = end;
    56  
    57    y[0] = f(ctx, x[0]);
    58    y[3] = f(ctx, x[3]);
    59  
    60    for (;;)
    61      {
    62        int i;
    63        int length = x[3] - x[0];
    64  
    65        x[1] = x[0] + length/3;
    66        x[2] = x[0] + 2*length/3;
    67  
    68        y[1] = f(ctx, x[1]);
    69        y[2] = f(ctx, x[2]);
    70  
    71  #if 0
    72        printf("%d: %f, %d: %f, %d:, %f %d: %f\n",
    73  	     x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]);
    74  #endif
    75        for (best_i = 0, i = 1; i < 4; i++)
    76  	if (y[i] < y[best_i])
    77  	  best_i = i;
    78  
    79        if (length <= 4)
    80  	break;
    81  
    82        if (best_i >= 2)
    83  	{
    84  	  x[0] = x[1];
    85  	  y[0] = y[1];
    86  	}
    87        else
    88  	{
    89  	  x[3] = x[2];
    90  	  y[3] = y[2];
    91  	}
    92      }
    93    *minp = y[best_i];
    94    return x[best_i];
    95  }
    96  
    97  static int
    98  compare_double(const void *ap, const void *bp)
    99  {
   100    double a = * (const double *) ap;
   101    double b = * (const double *) bp;
   102  
   103    if (a < b)
   104      return -1;
   105    else if (a > b)
   106      return 1;
   107    else
   108      return 0;
   109  }
   110  
   111  static double
   112  median (double *v, size_t n)
   113  {
   114    qsort(v, n, sizeof(*v), compare_double);
   115  
   116    return v[n/2];
   117  }
   118  
   119  #define TIME(res, code) do {				\
   120    double time_measurement[5];				\
   121    unsigned time_i;					\
   122  							\
   123    for (time_i = 0; time_i < 5; time_i++)		\
   124      {							\
   125        speed_starttime();				\
   126        code;						\
   127        time_measurement[time_i] = speed_endtime();	\
   128      }							\
   129    res = median(time_measurement, 5);			\
   130  } while (0)
   131  
   132  struct bench_data
   133  {
   134    mp_size_t n;
   135    mp_ptr ap;
   136    mp_ptr bp;
   137    mp_ptr up;
   138    mp_ptr vp;
   139    mp_ptr gp;
   140  };
   141  
   142  static double
   143  bench_gcd (void *ctx, int p)
   144  {
   145    struct bench_data *data = (struct bench_data *) ctx;
   146    double t;
   147  
   148    p_table[data->n] = p;
   149    TIME(t, {
   150        MPN_COPY (data->up, data->ap, data->n);
   151        MPN_COPY (data->vp, data->bp, data->n);
   152        mpn_gcd (data->gp, data->up, data->n, data->vp, data->n);
   153      });
   154  
   155    return t;
   156  }
   157  
   158  int
   159  main(int argc, char **argv)
   160  {
   161    gmp_randstate_t rands;  struct bench_data data;
   162    mp_size_t n;
   163  
   164    TMP_DECL;
   165  
   166    /* Unbuffered so if output is redirected to a file it isn't lost if the
   167       program is killed part way through.  */
   168    setbuf (stdout, NULL);
   169    setbuf (stderr, NULL);
   170  
   171    gmp_randinit_default (rands);
   172  
   173    TMP_MARK;
   174  
   175    data.ap = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
   176    data.bp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
   177    data.up = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
   178    data.vp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
   179    data.gp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
   180  
   181    mpn_random (data.ap, P_TABLE_SIZE);
   182    mpn_random (data.bp, P_TABLE_SIZE);
   183  
   184    memset (p_table, 0, sizeof(p_table));
   185  
   186    for (n = 100; n < P_TABLE_SIZE; n++)
   187      {
   188        mp_size_t p;
   189        mp_size_t best_p;
   190        double best_time;
   191        double lehmer_time;
   192  
   193        if (data.ap[n-1] == 0)
   194  	data.ap[n-1] = 1;
   195  
   196        if (data.bp[n-1] == 0)
   197  	data.bp[n-1] = 1;
   198  
   199        data.n = n;
   200  
   201        lehmer_time = bench_gcd (&data, 0);
   202  
   203        best_p = search (&best_time, bench_gcd, &data, n/5, 4*n/5);
   204        if (best_time > lehmer_time)
   205  	best_p = 0;
   206  
   207        printf("%6d %6d %5.3g", n, best_p, (double) best_p / n);
   208        if (best_p > 0)
   209  	{
   210  	  double speedup = 100 * (lehmer_time - best_time) / lehmer_time;
   211  	  printf(" %5.3g%%", speedup);
   212  	  if (speedup < 1.0)
   213  	    {
   214  	      printf(" (ignored)");
   215  	      best_p = 0;
   216  	    }
   217  	}
   218        printf("\n");
   219  
   220        p_table[n] = best_p;
   221      }
   222    TMP_FREE;
   223    gmp_randclear(rands);
   224    return 0;
   225  }