speed-ext.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:7k
源码类别:

数学计算

开发平台:

Unix_Linux

  1. /* An example of extending the speed program to measure routines not in GMP.
  2. Copyright 1999, 2000, 2002, 2003, 2005 Free Software Foundation, Inc.
  3. This file is part of the GNU MP Library.
  4. The GNU MP Library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or (at your
  7. option) any later version.
  8. The GNU MP Library is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  14. /* The extension here is three versions of an mpn arithmetic mean.  These
  15.    aren't meant to be particularly useful, just examples.
  16.    You can run something like the following to compare their speeds.
  17.            ./speed-ext -s 1-20 -c mean_calls mean_open mean_open2
  18.    On RISC chips, mean_open() might be fastest if the compiler is doing a
  19.    good job.  On the register starved x86s, mean_calls will be fastest.
  20.    Notes:
  21.    SPEED_EXTRA_PROTOS and SPEED_EXTRA_ROUTINES are macros that get expanded
  22.    by speed.c in useful places.  SPEED_EXTRA_PROTOS goes after the header
  23.    files, and SPEED_EXTRA_ROUTINES goes in the array of available routines.
  24.    The advantage of this #include "speed.c" scheme is that there's no
  25.    editing of a copy of that file, and new features in new versions of it
  26.    will be immediately available.
  27.    In a real program the routines mean_calls() etc would probably be in
  28.    separate C or assembler source files, and just the measuring
  29.    speed_mean_calls() etc would be here.  Linking against other libraries
  30.    for things to measure is perfectly possible too.
  31.    When attempting to compare two versions of the same named routine, say
  32.    like the generic and assembler versions of mpn_add_n(), creative use of
  33.    cc -D or #define is suggested, so one or both can be renamed and linked
  34.    into the same program.  It'll be much easier to compare them side by side
  35.    than with separate programs for each.
  36.    common.c has notes on writing speed measuring routines.
  37.    Remember to link against tune/libspeed.la (or tune/.libs/libspeed.a if
  38.    not using libtool) to get common.o and other objects needed by speed.c.  */
  39. #define SPEED_EXTRA_PROTOS                                              
  40.   double speed_mean_calls __GMP_PROTO ((struct speed_params *s));       
  41.   double speed_mean_open  __GMP_PROTO ((struct speed_params *s));       
  42.   double speed_mean_open2 __GMP_PROTO ((struct speed_params *s));
  43. #define SPEED_EXTRA_ROUTINES            
  44.   { "mean_calls",  speed_mean_calls  }, 
  45.   { "mean_open",   speed_mean_open   }, 
  46.   { "mean_open2",  speed_mean_open2  },
  47. #include "speed.c"
  48. /* A straightforward implementation calling mpn subroutines.
  49.    wp,size is set to (xp,size + yp,size) / 2.  The return value is the
  50.    remainder from the division.  The other versions are the same.  */
  51. mp_limb_t
  52. mean_calls (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
  53. {
  54.   mp_limb_t  c, ret;
  55.   ASSERT (size >= 1);
  56.   c = mpn_add_n (wp, xp, yp, size);
  57.   ret = mpn_rshift (wp, wp, size, 1) >> (GMP_LIMB_BITS-1);
  58.   wp[size-1] |= (c << (GMP_LIMB_BITS-1));
  59.   return ret;
  60. }
  61. /* An open-coded version, making one pass over the data.  The right shift is
  62.    done as the added limbs are produced.  The addition code follows
  63.    mpn/generic/add_n.c. */
  64. mp_limb_t
  65. mean_open (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
  66. {
  67.   mp_limb_t  w, wprev, x, y, c, ret;
  68.   mp_size_t  i;
  69.   ASSERT (size >= 1);
  70.   x = xp[0];
  71.   y = yp[0];
  72.   wprev = x + y;
  73.   c = (wprev < x);
  74.   ret = (wprev & 1);
  75. #define RSHIFT(hi,lo)   (((lo) >> 1) | ((hi) << (GMP_LIMB_BITS-1)))
  76.   for (i = 1; i < size; i++)
  77.     {
  78.       x = xp[i];
  79.       y = yp[i];
  80.       w = x + c;
  81.       c = (w < x);
  82.       w += y;
  83.       c += (w < y);
  84.       wp[i-1] = RSHIFT (w, wprev);
  85.       wprev = w;
  86.     }
  87.   wp[i-1] = RSHIFT (c, wprev);
  88.   return ret;
  89. }
  90. /* Another one-pass version, but right shifting the source limbs rather than
  91.    the result limbs.  There's not much chance of this being better than the
  92.    above, but it's an alternative at least. */
  93. mp_limb_t
  94. mean_open2 (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
  95. {
  96.   mp_limb_t  w, x, y, xnext, ynext, c, ret;
  97.   mp_size_t  i;
  98.   ASSERT (size >= 1);
  99.   x = xp[0];
  100.   y = yp[0];
  101.   /* ret is the low bit of x+y, c is the carry out of that low bit add */
  102.   ret = (x ^ y) & 1;
  103.   c   = (x & y) & 1;
  104.   for (i = 0; i < size-1; i++)
  105.     {
  106.       xnext = xp[i+1];
  107.       ynext = yp[i+1];
  108.       x = RSHIFT (xnext, x);
  109.       y = RSHIFT (ynext, y);
  110.       w = x + c;
  111.       c = (w < x);
  112.       w += y;
  113.       c += (w < y);
  114.       wp[i] = w;
  115.       x = xnext;
  116.       y = ynext;
  117.     }
  118.   wp[i] = (x >> 1) + (y >> 1) + c;
  119.   return ret;
  120. }
  121. /* The speed measuring routines are the same apart from which function they
  122.    run, so a macro is used.  Actually this macro is the same as
  123.    SPEED_ROUTINE_MPN_BINARY_N.  */
  124. #define SPEED_ROUTINE_MEAN(mean_fun)                    
  125.   {                                                     
  126.     unsigned  i;                                        
  127.     mp_ptr    wp;                                       
  128.     double    t;                                        
  129.     TMP_DECL;                                  
  130.                                                         
  131.     SPEED_RESTRICT_COND (s->size >= 1);                 
  132.                                                         
  133.     TMP_MARK;                                  
  134.     SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);   
  135.                                                         
  136.     speed_operand_src (s, s->xp, s->size);              
  137.     speed_operand_src (s, s->yp, s->size);              
  138.     speed_operand_dst (s, wp, s->size);                 
  139.     speed_cache_fill (s);                               
  140.                                                         
  141.     speed_starttime ();                                 
  142.     i = s->reps;                                        
  143.     do                                                  
  144.       mean_fun (wp, s->xp, s->yp, s->size);             
  145.     while (--i != 0);                                   
  146.     t = speed_endtime ();                               
  147.                                                         
  148.     TMP_FREE;                                  
  149.     return t;                                           
  150.   }
  151. double
  152. speed_mean_calls (struct speed_params *s)
  153. {
  154.   SPEED_ROUTINE_MEAN (mean_calls);
  155. }
  156. double
  157. speed_mean_open (struct speed_params *s)
  158. {
  159.   SPEED_ROUTINE_MEAN (mean_open);
  160. }
  161. double
  162. speed_mean_open2 (struct speed_params *s)
  163. {
  164.   SPEED_ROUTINE_MEAN (mean_open2);
  165. }