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

     1  /* gcd_subdiv_step.c.
     2  
     3     THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
     4     SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
     5     GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
     6  
     7  Copyright 2003-2005, 2008, 2010, 2011 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 <stdlib.h>		/* for NULL */
    36  
    37  #include "gmp.h"
    38  #include "gmp-impl.h"
    39  #include "longlong.h"
    40  
    41  /* Used when mpn_hgcd or mpn_hgcd2 has failed. Then either one of a or
    42     b is small, or the difference is small. Perform one subtraction
    43     followed by one division. The normal case is to compute the reduced
    44     a and b, and return the new size.
    45  
    46     If s == 0 (used for gcd and gcdext), returns zero if the gcd is
    47     found.
    48  
    49     If s > 0, don't reduce to size <= s, and return zero if no
    50     reduction is possible (if either a, b or |a-b| is of size <= s). */
    51  
    52  /* The hook function is called as
    53  
    54       hook(ctx, gp, gn, qp, qn, d)
    55  
    56     in the following cases:
    57  
    58     + If A = B at the start, G is the gcd, Q is NULL, d = -1.
    59  
    60     + If one input is zero at the start, G is the gcd, Q is NULL,
    61       d = 0 if A = G and d = 1 if B = G.
    62  
    63     Otherwise, if d = 0 we have just subtracted a multiple of A from B,
    64     and if d = 1 we have subtracted a multiple of B from A.
    65  
    66     + If A = B after subtraction, G is the gcd, Q is NULL.
    67  
    68     + If we get a zero remainder after division, G is the gcd, Q is the
    69       quotient.
    70  
    71     + Otherwise, G is NULL, Q is the quotient (often 1).
    72  
    73   */
    74  
    75  mp_size_t
    76  mpn_gcd_subdiv_step (mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t s,
    77  		     gcd_subdiv_step_hook *hook, void *ctx,
    78  		     mp_ptr tp)
    79  {
    80    static const mp_limb_t one = CNST_LIMB(1);
    81    mp_size_t an, bn, qn;
    82  
    83    int swapped;
    84  
    85    ASSERT (n > 0);
    86    ASSERT (ap[n-1] > 0 || bp[n-1] > 0);
    87  
    88    an = bn = n;
    89    MPN_NORMALIZE (ap, an);
    90    MPN_NORMALIZE (bp, bn);
    91  
    92    swapped = 0;
    93  
    94    /* Arrange so that a < b, subtract b -= a, and maintain
    95       normalization. */
    96    if (an == bn)
    97      {
    98        int c;
    99        MPN_CMP (c, ap, bp, an);
   100        if (UNLIKELY (c == 0))
   101  	{
   102  	  /* For gcdext, return the smallest of the two cofactors, so
   103  	     pass d = -1. */
   104  	  if (s == 0)
   105  	    hook (ctx, ap, an, NULL, 0, -1);
   106  	  return 0;
   107  	}
   108        else if (c > 0)
   109  	{
   110  	  MP_PTR_SWAP (ap, bp);
   111  	  swapped ^= 1;
   112  	}
   113      }
   114    else
   115      {
   116        if (an > bn)
   117  	{
   118  	  MPN_PTR_SWAP (ap, an, bp, bn);
   119  	  swapped ^= 1;
   120  	}
   121      }
   122    if (an <= s)
   123      {
   124        if (s == 0)
   125  	hook (ctx, bp, bn, NULL, 0, swapped ^ 1);
   126        return 0;
   127      }
   128  
   129    ASSERT_NOCARRY (mpn_sub (bp, bp, bn, ap, an));
   130    MPN_NORMALIZE (bp, bn);
   131    ASSERT (bn > 0);
   132  
   133    if (bn <= s)
   134      {
   135        /* Undo subtraction. */
   136        mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
   137        if (cy > 0)
   138  	bp[an] = cy;
   139        return 0;
   140      }
   141  
   142    /* Arrange so that a < b */
   143    if (an == bn)
   144      {
   145        int c;
   146        MPN_CMP (c, ap, bp, an);
   147        if (UNLIKELY (c == 0))
   148  	{
   149  	  if (s > 0)
   150  	    /* Just record subtraction and return */
   151  	    hook (ctx, NULL, 0, &one, 1, swapped);
   152  	  else
   153  	    /* Found gcd. */
   154  	    hook (ctx, bp, bn, NULL, 0, swapped);
   155  	  return 0;
   156  	}
   157  
   158        hook (ctx, NULL, 0, &one, 1, swapped);
   159  
   160        if (c > 0)
   161  	{
   162  	  MP_PTR_SWAP (ap, bp);
   163  	  swapped ^= 1;
   164  	}
   165      }
   166    else
   167      {
   168        hook (ctx, NULL, 0, &one, 1, swapped);
   169  
   170        if (an > bn)
   171  	{
   172  	  MPN_PTR_SWAP (ap, an, bp, bn);
   173  	  swapped ^= 1;
   174  	}
   175      }
   176  
   177    mpn_tdiv_qr (tp, bp, 0, bp, bn, ap, an);
   178    qn = bn - an + 1;
   179    bn = an;
   180    MPN_NORMALIZE (bp, bn);
   181  
   182    if (UNLIKELY (bn <= s))
   183      {
   184        if (s == 0)
   185  	{
   186  	  hook (ctx, ap, an, tp, qn, swapped);
   187  	  return 0;
   188  	}
   189  
   190        /* Quotient is one too large, so decrement it and add back A. */
   191        if (bn > 0)
   192  	{
   193  	  mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
   194  	  if (cy)
   195  	    bp[an++] = cy;
   196  	}
   197        else
   198  	MPN_COPY (bp, ap, an);
   199  
   200        MPN_DECR_U (tp, qn, 1);
   201      }
   202  
   203    hook (ctx, NULL, 0, tp, qn, swapped);
   204    return an;
   205  }