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

     1  /* mpn_gcdext -- Extended Greatest Common Divisor.
     2  
     3  Copyright 1996, 1998, 2000-2005, 2008, 2009, 2012 Free Software Foundation,
     4  Inc.
     5  
     6  This file is part of the GNU MP Library.
     7  
     8  The GNU MP Library is free software; you can redistribute it and/or modify
     9  it under the terms of either:
    10  
    11    * the GNU Lesser General Public License as published by the Free
    12      Software Foundation; either version 3 of the License, or (at your
    13      option) any later version.
    14  
    15  or
    16  
    17    * the GNU General Public License as published by the Free Software
    18      Foundation; either version 2 of the License, or (at your option) any
    19      later version.
    20  
    21  or both in parallel, as here.
    22  
    23  The GNU MP Library is distributed in the hope that it will be useful, but
    24  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    25  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    26  for more details.
    27  
    28  You should have received copies of the GNU General Public License and the
    29  GNU Lesser General Public License along with the GNU MP Library.  If not,
    30  see https://www.gnu.org/licenses/.  */
    31  
    32  #include "gmp.h"
    33  #include "gmp-impl.h"
    34  #include "longlong.h"
    35  
    36  /* Here, d is the index of the cofactor to update. FIXME: Could use qn
    37     = 0 for the common case q = 1. */
    38  void
    39  mpn_gcdext_hook (void *p, mp_srcptr gp, mp_size_t gn,
    40  		 mp_srcptr qp, mp_size_t qn, int d)
    41  {
    42    struct gcdext_ctx *ctx = (struct gcdext_ctx *) p;
    43    mp_size_t un = ctx->un;
    44  
    45    if (gp)
    46      {
    47        mp_srcptr up;
    48  
    49        ASSERT (gn > 0);
    50        ASSERT (gp[gn-1] > 0);
    51  
    52        MPN_COPY (ctx->gp, gp, gn);
    53        ctx->gn = gn;
    54  
    55        if (d < 0)
    56  	{
    57  	  int c;
    58  
    59  	  /* Must return the smallest cofactor, +u1 or -u0 */
    60  	  MPN_CMP (c, ctx->u0, ctx->u1, un);
    61  	  ASSERT (c != 0 || (un == 1 && ctx->u0[0] == 1 && ctx->u1[0] == 1));
    62  
    63  	  d = c < 0;
    64  	}
    65  
    66        up = d ? ctx->u0 : ctx->u1;
    67  
    68        MPN_NORMALIZE (up, un);
    69        MPN_COPY (ctx->up, up, un);
    70  
    71        *ctx->usize = d ? -un : un;
    72      }
    73    else
    74      {
    75        mp_limb_t cy;
    76        mp_ptr u0 = ctx->u0;
    77        mp_ptr u1 = ctx->u1;
    78  
    79        ASSERT (d >= 0);
    80  
    81        if (d)
    82  	MP_PTR_SWAP (u0, u1);
    83  
    84        qn -= (qp[qn-1] == 0);
    85  
    86        /* Update u0 += q  * u1 */
    87        if (qn == 1)
    88  	{
    89  	  mp_limb_t q = qp[0];
    90  
    91  	  if (q == 1)
    92  	    /* A common case. */
    93  	    cy = mpn_add_n (u0, u0, u1, un);
    94  	  else
    95  	    cy = mpn_addmul_1 (u0, u1, un, q);
    96  	}
    97        else
    98  	{
    99  	  mp_size_t u1n;
   100  	  mp_ptr tp;
   101  
   102  	  u1n = un;
   103  	  MPN_NORMALIZE (u1, u1n);
   104  
   105  	  if (u1n == 0)
   106  	    return;
   107  
   108  	  /* Should always have u1n == un here, and u1 >= u0. The
   109  	     reason is that we alternate adding u0 to u1 and u1 to u0
   110  	     (corresponding to subtractions a - b and b - a), and we
   111  	     can get a large quotient only just after a switch, which
   112  	     means that we'll add (a multiple of) the larger u to the
   113  	     smaller. */
   114  
   115  	  tp = ctx->tp;
   116  
   117  	  if (qn > u1n)
   118  	    mpn_mul (tp, qp, qn, u1, u1n);
   119  	  else
   120  	    mpn_mul (tp, u1, u1n, qp, qn);
   121  
   122  	  u1n += qn;
   123  	  u1n -= tp[u1n-1] == 0;
   124  
   125  	  if (u1n >= un)
   126  	    {
   127  	      cy = mpn_add (u0, tp, u1n, u0, un);
   128  	      un = u1n;
   129  	    }
   130  	  else
   131  	    /* Note: Unlikely case, maybe never happens? */
   132  	    cy = mpn_add (u0, u0, un, tp, u1n);
   133  
   134  	}
   135        u0[un] = cy;
   136        ctx->un = un + (cy > 0);
   137      }
   138  }
   139  
   140  /* Temporary storage: 3*(n+1) for u. If hgcd2 succeeds, we need n for
   141     the matrix-vector multiplication adjusting a, b. If hgcd fails, we
   142     need at most n for the quotient and n+1 for the u update (reusing
   143     the extra u). In all, 4n + 3. */
   144  
   145  mp_size_t
   146  mpn_gcdext_lehmer_n (mp_ptr gp, mp_ptr up, mp_size_t *usize,
   147  		     mp_ptr ap, mp_ptr bp, mp_size_t n,
   148  		     mp_ptr tp)
   149  {
   150    mp_size_t ualloc = n + 1;
   151  
   152    /* Keeps track of the second row of the reduction matrix
   153     *
   154     *   M = (v0, v1 ; u0, u1)
   155     *
   156     * which correspond to the first column of the inverse
   157     *
   158     *   M^{-1} = (u1, -v1; -u0, v0)
   159     *
   160     * This implies that
   161     *
   162     *   a =  u1 A (mod B)
   163     *   b = -u0 A (mod B)
   164     *
   165     * where A, B denotes the input values.
   166     */
   167  
   168    struct gcdext_ctx ctx;
   169    mp_size_t un;
   170    mp_ptr u0;
   171    mp_ptr u1;
   172    mp_ptr u2;
   173  
   174    MPN_ZERO (tp, 3*ualloc);
   175    u0 = tp; tp += ualloc;
   176    u1 = tp; tp += ualloc;
   177    u2 = tp; tp += ualloc;
   178  
   179    u1[0] = 1; un = 1;
   180  
   181    ctx.gp = gp;
   182    ctx.up = up;
   183    ctx.usize = usize;
   184  
   185    /* FIXME: Handle n == 2 differently, after the loop? */
   186    while (n >= 2)
   187      {
   188        struct hgcd_matrix1 M;
   189        mp_limb_t ah, al, bh, bl;
   190        mp_limb_t mask;
   191  
   192        mask = ap[n-1] | bp[n-1];
   193        ASSERT (mask > 0);
   194  
   195        if (mask & GMP_NUMB_HIGHBIT)
   196  	{
   197  	  ah = ap[n-1]; al = ap[n-2];
   198  	  bh = bp[n-1]; bl = bp[n-2];
   199  	}
   200        else if (n == 2)
   201  	{
   202  	  /* We use the full inputs without truncation, so we can
   203  	     safely shift left. */
   204  	  int shift;
   205  
   206  	  count_leading_zeros (shift, mask);
   207  	  ah = MPN_EXTRACT_NUMB (shift, ap[1], ap[0]);
   208  	  al = ap[0] << shift;
   209  	  bh = MPN_EXTRACT_NUMB (shift, bp[1], bp[0]);
   210  	  bl = bp[0] << shift;
   211  	}
   212        else
   213  	{
   214  	  int shift;
   215  
   216  	  count_leading_zeros (shift, mask);
   217  	  ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
   218  	  al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
   219  	  bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
   220  	  bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
   221  	}
   222  
   223        /* Try an mpn_nhgcd2 step */
   224        if (mpn_hgcd2 (ah, al, bh, bl, &M))
   225  	{
   226  	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
   227  	  MP_PTR_SWAP (ap, tp);
   228  	  un = mpn_hgcd_mul_matrix1_vector(&M, u2, u0, u1, un);
   229  	  MP_PTR_SWAP (u0, u2);
   230  	}
   231        else
   232  	{
   233  	  /* mpn_hgcd2 has failed. Then either one of a or b is very
   234  	     small, or the difference is very small. Perform one
   235  	     subtraction followed by one division. */
   236  	  ctx.u0 = u0;
   237  	  ctx.u1 = u1;
   238  	  ctx.tp = u2;
   239  	  ctx.un = un;
   240  
   241  	  /* Temporary storage n for the quotient and ualloc for the
   242  	     new cofactor. */
   243  	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
   244  	  if (n == 0)
   245  	    return ctx.gn;
   246  
   247  	  un = ctx.un;
   248  	}
   249      }
   250    ASSERT_ALWAYS (ap[0] > 0);
   251    ASSERT_ALWAYS (bp[0] > 0);
   252  
   253    if (ap[0] == bp[0])
   254      {
   255        int c;
   256  
   257        /* Which cofactor to return now? Candidates are +u1 and -u0,
   258  	 depending on which of a and b was most recently reduced,
   259  	 which we don't keep track of. So compare and get the smallest
   260  	 one. */
   261  
   262        gp[0] = ap[0];
   263  
   264        MPN_CMP (c, u0, u1, un);
   265        ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
   266        if (c < 0)
   267  	{
   268  	  MPN_NORMALIZE (u0, un);
   269  	  MPN_COPY (up, u0, un);
   270  	  *usize = -un;
   271  	}
   272        else
   273  	{
   274  	  MPN_NORMALIZE_NOT_ZERO (u1, un);
   275  	  MPN_COPY (up, u1, un);
   276  	  *usize = un;
   277  	}
   278        return 1;
   279      }
   280    else
   281      {
   282        mp_limb_t uh, vh;
   283        mp_limb_signed_t u;
   284        mp_limb_signed_t v;
   285        int negate;
   286  
   287        gp[0] = mpn_gcdext_1 (&u, &v, ap[0], bp[0]);
   288  
   289        /* Set up = u u1 - v u0. Keep track of size, un grows by one or
   290  	 two limbs. */
   291  
   292        if (u == 0)
   293  	{
   294  	  ASSERT (v == 1);
   295  	  MPN_NORMALIZE (u0, un);
   296  	  MPN_COPY (up, u0, un);
   297  	  *usize = -un;
   298  	  return 1;
   299  	}
   300        else if (v == 0)
   301  	{
   302  	  ASSERT (u == 1);
   303  	  MPN_NORMALIZE (u1, un);
   304  	  MPN_COPY (up, u1, un);
   305  	  *usize = un;
   306  	  return 1;
   307  	}
   308        else if (u > 0)
   309  	{
   310  	  negate = 0;
   311  	  ASSERT (v < 0);
   312  	  v = -v;
   313  	}
   314        else
   315  	{
   316  	  negate = 1;
   317  	  ASSERT (v > 0);
   318  	  u = -u;
   319  	}
   320  
   321        uh = mpn_mul_1 (up, u1, un, u);
   322        vh = mpn_addmul_1 (up, u0, un, v);
   323  
   324        if ( (uh | vh) > 0)
   325  	{
   326  	  uh += vh;
   327  	  up[un++] = uh;
   328  	  if (uh < vh)
   329  	    up[un++] = 1;
   330  	}
   331  
   332        MPN_NORMALIZE_NOT_ZERO (up, un);
   333  
   334        *usize = negate ? -un : un;
   335        return 1;
   336      }
   337  }