github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpn/generic/mod_34lsub1.c (about)

     1  /* mpn_mod_34lsub1 -- remainder modulo 2^(GMP_NUMB_BITS*3/4)-1.
     2  
     3     THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
     4     CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
     5     FUTURE GNU MP RELEASES.
     6  
     7  Copyright 2000-2002 Free Software Foundation, Inc.
     8  
     9  This file is part of the GNU MP Library.
    10  
    11  The GNU MP Library is free software; you can redistribute it and/or modify
    12  it under the terms of either:
    13  
    14    * the GNU Lesser General Public License as published by the Free
    15      Software Foundation; either version 3 of the License, or (at your
    16      option) any later version.
    17  
    18  or
    19  
    20    * the GNU General Public License as published by the Free Software
    21      Foundation; either version 2 of the License, or (at your option) any
    22      later version.
    23  
    24  or both in parallel, as here.
    25  
    26  The GNU MP Library is distributed in the hope that it will be useful, but
    27  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    28  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    29  for more details.
    30  
    31  You should have received copies of the GNU General Public License and the
    32  GNU Lesser General Public License along with the GNU MP Library.  If not,
    33  see https://www.gnu.org/licenses/.  */
    34  
    35  
    36  #include "gmp.h"
    37  #include "gmp-impl.h"
    38  
    39  
    40  /* Calculate a remainder from {p,n} divided by 2^(GMP_NUMB_BITS*3/4)-1.
    41     The remainder is not fully reduced, it's any limb value congruent to
    42     {p,n} modulo that divisor.
    43  
    44     This implementation is only correct when GMP_NUMB_BITS is a multiple of
    45     4.
    46  
    47     FIXME: If GMP_NAIL_BITS is some silly big value during development then
    48     it's possible the carry accumulators c0,c1,c2 could overflow.
    49  
    50     General notes:
    51  
    52     The basic idea is to use a set of N accumulators (N=3 in this case) to
    53     effectively get a remainder mod 2^(GMP_NUMB_BITS*N)-1 followed at the end
    54     by a reduction to GMP_NUMB_BITS*N/M bits (M=4 in this case) for a
    55     remainder mod 2^(GMP_NUMB_BITS*N/M)-1.  N and M are chosen to give a good
    56     set of small prime factors in 2^(GMP_NUMB_BITS*N/M)-1.
    57  
    58     N=3 M=4 suits GMP_NUMB_BITS==32 and GMP_NUMB_BITS==64 quite well, giving
    59     a few more primes than a single accumulator N=1 does, and for no extra
    60     cost (assuming the processor has a decent number of registers).
    61  
    62     For strange nailified values of GMP_NUMB_BITS the idea would be to look
    63     for what N and M give good primes.  With GMP_NUMB_BITS not a power of 2
    64     the choices for M may be opened up a bit.  But such things are probably
    65     best done in separate code, not grafted on here.  */
    66  
    67  #if GMP_NUMB_BITS % 4 == 0
    68  
    69  #define B1  (GMP_NUMB_BITS / 4)
    70  #define B2  (B1 * 2)
    71  #define B3  (B1 * 3)
    72  
    73  #define M1  ((CNST_LIMB(1) << B1) - 1)
    74  #define M2  ((CNST_LIMB(1) << B2) - 1)
    75  #define M3  ((CNST_LIMB(1) << B3) - 1)
    76  
    77  #define LOW0(n)      ((n) & M3)
    78  #define HIGH0(n)     ((n) >> B3)
    79  
    80  #define LOW1(n)      (((n) & M2) << B1)
    81  #define HIGH1(n)     ((n) >> B2)
    82  
    83  #define LOW2(n)      (((n) & M1) << B2)
    84  #define HIGH2(n)     ((n) >> B1)
    85  
    86  #define PARTS0(n)    (LOW0(n) + HIGH0(n))
    87  #define PARTS1(n)    (LOW1(n) + HIGH1(n))
    88  #define PARTS2(n)    (LOW2(n) + HIGH2(n))
    89  
    90  #define ADD(c,a,val)                    \
    91    do {                                  \
    92      mp_limb_t  new_c;                   \
    93      ADDC_LIMB (new_c, a, a, val);       \
    94      (c) += new_c;                       \
    95    } while (0)
    96  
    97  mp_limb_t
    98  mpn_mod_34lsub1 (mp_srcptr p, mp_size_t n)
    99  {
   100    mp_limb_t  c0 = 0;
   101    mp_limb_t  c1 = 0;
   102    mp_limb_t  c2 = 0;
   103    mp_limb_t  a0, a1, a2;
   104  
   105    ASSERT (n >= 1);
   106    ASSERT (n/3 < GMP_NUMB_MAX);
   107  
   108    a0 = a1 = a2 = 0;
   109    c0 = c1 = c2 = 0;
   110  
   111    while ((n -= 3) >= 0)
   112      {
   113        ADD (c0, a0, p[0]);
   114        ADD (c1, a1, p[1]);
   115        ADD (c2, a2, p[2]);
   116        p += 3;
   117      }
   118  
   119    if (n != -3)
   120      {
   121        ADD (c0, a0, p[0]);
   122        if (n != -2)
   123  	ADD (c1, a1, p[1]);
   124      }
   125  
   126    return
   127      PARTS0 (a0) + PARTS1 (a1) + PARTS2 (a2)
   128      + PARTS1 (c0) + PARTS2 (c1) + PARTS0 (c2);
   129  }
   130  
   131  #endif