github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpz/aorsmul_i.c (about)

     1  /* mpz_addmul_ui, mpz_submul_ui - add or subtract small multiple.
     2  
     3     THE mpz_aorsmul_1 FUNCTION IN THIS FILE IS FOR INTERNAL USE ONLY AND IS
     4     ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
     5     COMPLETELY IN FUTURE GNU MP RELEASES.
     6  
     7  Copyright 2001, 2002, 2004, 2005, 2012 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  #include "gmp.h"
    36  #include "gmp-impl.h"
    37  
    38  
    39  #if HAVE_NATIVE_mpn_mul_1c
    40  #define MPN_MUL_1C(cout, dst, src, size, n, cin)        \
    41    do {                                                  \
    42      (cout) = mpn_mul_1c (dst, src, size, n, cin);       \
    43    } while (0)
    44  #else
    45  #define MPN_MUL_1C(cout, dst, src, size, n, cin)        \
    46    do {                                                  \
    47      mp_limb_t __cy;                                     \
    48      __cy = mpn_mul_1 (dst, src, size, n);               \
    49      (cout) = __cy + mpn_add_1 (dst, dst, size, cin);    \
    50    } while (0)
    51  #endif
    52  
    53  
    54  /* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
    55  
    56     All that's needed to account for negative w or x is to flip "sub".
    57  
    58     The final w will retain its sign, unless an underflow occurs in a submul
    59     of absolute values, in which case it's flipped.
    60  
    61     If x has more limbs than w, then mpn_submul_1 followed by mpn_com is
    62     used.  The alternative would be mpn_mul_1 into temporary space followed
    63     by mpn_sub_n.  Avoiding temporary space seem good, and submul+com stands
    64     a chance of being faster since it involves only one set of carry
    65     propagations, not two.  Note that doing an addmul_1 with a
    66     twos-complement negative y doesn't work, because it effectively adds an
    67     extra x * 2^GMP_LIMB_BITS.  */
    68  
    69  REGPARM_ATTR(1) void
    70  mpz_aorsmul_1 (mpz_ptr w, mpz_srcptr x, mp_limb_t y, mp_size_t sub)
    71  {
    72    mp_size_t  xsize, wsize, wsize_signed, new_wsize, min_size, dsize;
    73    mp_srcptr  xp;
    74    mp_ptr     wp;
    75    mp_limb_t  cy;
    76  
    77    /* w unaffected if x==0 or y==0 */
    78    xsize = SIZ (x);
    79    if (xsize == 0 || y == 0)
    80      return;
    81  
    82    sub ^= xsize;
    83    xsize = ABS (xsize);
    84  
    85    wsize_signed = SIZ (w);
    86    if (wsize_signed == 0)
    87      {
    88        /* nothing to add to, just set x*y, "sub" gives the sign */
    89        wp = MPZ_REALLOC (w, xsize+1);
    90        cy = mpn_mul_1 (wp, PTR(x), xsize, y);
    91        wp[xsize] = cy;
    92        xsize += (cy != 0);
    93        SIZ (w) = (sub >= 0 ? xsize : -xsize);
    94        return;
    95      }
    96  
    97    sub ^= wsize_signed;
    98    wsize = ABS (wsize_signed);
    99  
   100    new_wsize = MAX (wsize, xsize);
   101    wp = MPZ_REALLOC (w, new_wsize+1);
   102    xp = PTR (x);
   103    min_size = MIN (wsize, xsize);
   104  
   105    if (sub >= 0)
   106      {
   107        /* addmul of absolute values */
   108  
   109        cy = mpn_addmul_1 (wp, xp, min_size, y);
   110        wp += min_size;
   111        xp += min_size;
   112  
   113        dsize = xsize - wsize;
   114  #if HAVE_NATIVE_mpn_mul_1c
   115        if (dsize > 0)
   116  	cy = mpn_mul_1c (wp, xp, dsize, y, cy);
   117        else if (dsize < 0)
   118  	{
   119  	  dsize = -dsize;
   120  	  cy = mpn_add_1 (wp, wp, dsize, cy);
   121  	}
   122  #else
   123        if (dsize != 0)
   124  	{
   125  	  mp_limb_t  cy2;
   126  	  if (dsize > 0)
   127  	    cy2 = mpn_mul_1 (wp, xp, dsize, y);
   128  	  else
   129  	    {
   130  	      dsize = -dsize;
   131  	      cy2 = 0;
   132  	    }
   133  	  cy = cy2 + mpn_add_1 (wp, wp, dsize, cy);
   134  	}
   135  #endif
   136  
   137        wp[dsize] = cy;
   138        new_wsize += (cy != 0);
   139      }
   140    else
   141      {
   142        /* submul of absolute values */
   143  
   144        cy = mpn_submul_1 (wp, xp, min_size, y);
   145        if (wsize >= xsize)
   146  	{
   147  	  /* if w bigger than x, then propagate borrow through it */
   148  	  if (wsize != xsize)
   149  	    cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy);
   150  
   151  	  if (cy != 0)
   152  	    {
   153  	      /* Borrow out of w, take twos complement negative to get
   154  		 absolute value, flip sign of w.  */
   155  	      wp[new_wsize] = ~-cy;  /* extra limb is 0-cy */
   156  	      mpn_com (wp, wp, new_wsize);
   157  	      new_wsize++;
   158  	      MPN_INCR_U (wp, new_wsize, CNST_LIMB(1));
   159  	      wsize_signed = -wsize_signed;
   160  	    }
   161  	}
   162        else /* wsize < xsize */
   163  	{
   164  	  /* x bigger than w, so want x*y-w.  Submul has given w-x*y, so
   165  	     take twos complement and use an mpn_mul_1 for the rest.  */
   166  
   167  	  mp_limb_t  cy2;
   168  
   169  	  /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */
   170  	  mpn_com (wp, wp, wsize);
   171  	  cy += mpn_add_1 (wp, wp, wsize, CNST_LIMB(1));
   172  	  cy -= 1;
   173  
   174  	  /* If cy-1 == -1 then hold that -1 for latter.  mpn_submul_1 never
   175  	     returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */
   176  	  cy2 = (cy == MP_LIMB_T_MAX);
   177  	  cy += cy2;
   178  	  MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy);
   179  	  wp[new_wsize] = cy;
   180  	  new_wsize += (cy != 0);
   181  
   182  	  /* Apply any -1 from above.  The value at wp+wsize is non-zero
   183  	     because y!=0 and the high limb of x will be non-zero.  */
   184  	  if (cy2)
   185  	    MPN_DECR_U (wp+wsize, new_wsize-wsize, CNST_LIMB(1));
   186  
   187  	  wsize_signed = -wsize_signed;
   188  	}
   189  
   190        /* submul can produce high zero limbs due to cancellation, both when w
   191  	 has more limbs or x has more  */
   192        MPN_NORMALIZE (wp, new_wsize);
   193      }
   194  
   195    SIZ (w) = (wsize_signed >= 0 ? new_wsize : -new_wsize);
   196  
   197    ASSERT (new_wsize == 0 || PTR(w)[new_wsize-1] != 0);
   198  }
   199  
   200  
   201  void
   202  mpz_addmul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
   203  {
   204  #if BITS_PER_ULONG > GMP_NUMB_BITS
   205    if (UNLIKELY (y > GMP_NUMB_MAX))
   206      {
   207        mpz_t t;
   208        mp_ptr tp;
   209        mp_size_t xn;
   210        TMP_DECL;
   211        TMP_MARK;
   212        xn = SIZ (x);
   213        if (xn == 0) return;
   214        MPZ_TMP_INIT (t, ABS (xn) + 1);
   215        tp = PTR (t);
   216        tp[0] = 0;
   217        MPN_COPY (tp + 1, PTR(x), ABS (xn));
   218        SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
   219        mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) 0);
   220        PTR(t) = tp + 1;
   221        SIZ(t) = xn;
   222        mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) 0);
   223        TMP_FREE;
   224        return;
   225      }
   226  #endif
   227    mpz_aorsmul_1 (w, x, (mp_limb_t) y, (mp_size_t) 0);
   228  }
   229  
   230  void
   231  mpz_submul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
   232  {
   233  #if BITS_PER_ULONG > GMP_NUMB_BITS
   234    if (y > GMP_NUMB_MAX)
   235      {
   236        mpz_t t;
   237        mp_ptr tp;
   238        mp_size_t xn;
   239        TMP_DECL;
   240        TMP_MARK;
   241        xn = SIZ (x);
   242        if (xn == 0) return;
   243        MPZ_TMP_INIT (t, ABS (xn) + 1);
   244        tp = PTR (t);
   245        tp[0] = 0;
   246        MPN_COPY (tp + 1, PTR(x), ABS (xn));
   247        SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
   248        mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) -1);
   249        PTR(t) = tp + 1;
   250        SIZ(t) = xn;
   251        mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
   252        TMP_FREE;
   253        return;
   254      }
   255  #endif
   256    mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
   257  }