Home | History | Annotate | Line # | Download | only in generic
      1      1.1  mrg /* gcd_subdiv_step.c.
      2      1.1  mrg 
      3      1.1  mrg    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
      4      1.1  mrg    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
      5      1.1  mrg    GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
      6      1.1  mrg 
      7  1.1.1.3  mrg Copyright 2003-2005, 2008, 2010, 2011 Free Software Foundation, Inc.
      8      1.1  mrg 
      9      1.1  mrg This file is part of the GNU MP Library.
     10      1.1  mrg 
     11      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
     12  1.1.1.3  mrg it under the terms of either:
     13  1.1.1.3  mrg 
     14  1.1.1.3  mrg   * the GNU Lesser General Public License as published by the Free
     15  1.1.1.3  mrg     Software Foundation; either version 3 of the License, or (at your
     16  1.1.1.3  mrg     option) any later version.
     17  1.1.1.3  mrg 
     18  1.1.1.3  mrg or
     19  1.1.1.3  mrg 
     20  1.1.1.3  mrg   * the GNU General Public License as published by the Free Software
     21  1.1.1.3  mrg     Foundation; either version 2 of the License, or (at your option) any
     22  1.1.1.3  mrg     later version.
     23  1.1.1.3  mrg 
     24  1.1.1.3  mrg or both in parallel, as here.
     25      1.1  mrg 
     26      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     27      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     28  1.1.1.3  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     29  1.1.1.3  mrg for more details.
     30      1.1  mrg 
     31  1.1.1.3  mrg You should have received copies of the GNU General Public License and the
     32  1.1.1.3  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     33  1.1.1.3  mrg see https://www.gnu.org/licenses/.  */
     34      1.1  mrg 
     35  1.1.1.2  mrg #include <stdlib.h>		/* for NULL */
     36  1.1.1.2  mrg 
     37      1.1  mrg #include "gmp-impl.h"
     38      1.1  mrg #include "longlong.h"
     39      1.1  mrg 
     40      1.1  mrg /* Used when mpn_hgcd or mpn_hgcd2 has failed. Then either one of a or
     41      1.1  mrg    b is small, or the difference is small. Perform one subtraction
     42  1.1.1.2  mrg    followed by one division. The normal case is to compute the reduced
     43  1.1.1.2  mrg    a and b, and return the new size.
     44  1.1.1.2  mrg 
     45  1.1.1.2  mrg    If s == 0 (used for gcd and gcdext), returns zero if the gcd is
     46  1.1.1.2  mrg    found.
     47  1.1.1.2  mrg 
     48  1.1.1.2  mrg    If s > 0, don't reduce to size <= s, and return zero if no
     49  1.1.1.2  mrg    reduction is possible (if either a, b or |a-b| is of size <= s). */
     50  1.1.1.2  mrg 
     51  1.1.1.2  mrg /* The hook function is called as
     52  1.1.1.2  mrg 
     53  1.1.1.2  mrg      hook(ctx, gp, gn, qp, qn, d)
     54  1.1.1.2  mrg 
     55  1.1.1.2  mrg    in the following cases:
     56  1.1.1.2  mrg 
     57  1.1.1.2  mrg    + If A = B at the start, G is the gcd, Q is NULL, d = -1.
     58  1.1.1.2  mrg 
     59  1.1.1.2  mrg    + If one input is zero at the start, G is the gcd, Q is NULL,
     60  1.1.1.2  mrg      d = 0 if A = G and d = 1 if B = G.
     61  1.1.1.2  mrg 
     62  1.1.1.2  mrg    Otherwise, if d = 0 we have just subtracted a multiple of A from B,
     63  1.1.1.2  mrg    and if d = 1 we have subtracted a multiple of B from A.
     64  1.1.1.2  mrg 
     65  1.1.1.2  mrg    + If A = B after subtraction, G is the gcd, Q is NULL.
     66  1.1.1.2  mrg 
     67  1.1.1.2  mrg    + If we get a zero remainder after division, G is the gcd, Q is the
     68  1.1.1.2  mrg      quotient.
     69  1.1.1.2  mrg 
     70  1.1.1.2  mrg    + Otherwise, G is NULL, Q is the quotient (often 1).
     71  1.1.1.2  mrg 
     72  1.1.1.2  mrg  */
     73      1.1  mrg 
     74      1.1  mrg mp_size_t
     75  1.1.1.2  mrg mpn_gcd_subdiv_step (mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t s,
     76  1.1.1.2  mrg 		     gcd_subdiv_step_hook *hook, void *ctx,
     77  1.1.1.2  mrg 		     mp_ptr tp)
     78      1.1  mrg {
     79  1.1.1.2  mrg   static const mp_limb_t one = CNST_LIMB(1);
     80  1.1.1.2  mrg   mp_size_t an, bn, qn;
     81  1.1.1.2  mrg 
     82  1.1.1.2  mrg   int swapped;
     83      1.1  mrg 
     84      1.1  mrg   ASSERT (n > 0);
     85      1.1  mrg   ASSERT (ap[n-1] > 0 || bp[n-1] > 0);
     86      1.1  mrg 
     87      1.1  mrg   an = bn = n;
     88      1.1  mrg   MPN_NORMALIZE (ap, an);
     89      1.1  mrg   MPN_NORMALIZE (bp, bn);
     90      1.1  mrg 
     91  1.1.1.2  mrg   swapped = 0;
     92      1.1  mrg 
     93  1.1.1.2  mrg   /* Arrange so that a < b, subtract b -= a, and maintain
     94      1.1  mrg      normalization. */
     95  1.1.1.2  mrg   if (an == bn)
     96      1.1  mrg     {
     97      1.1  mrg       int c;
     98      1.1  mrg       MPN_CMP (c, ap, bp, an);
     99      1.1  mrg       if (UNLIKELY (c == 0))
    100  1.1.1.2  mrg 	{
    101  1.1.1.2  mrg 	  /* For gcdext, return the smallest of the two cofactors, so
    102  1.1.1.2  mrg 	     pass d = -1. */
    103  1.1.1.2  mrg 	  if (s == 0)
    104  1.1.1.2  mrg 	    hook (ctx, ap, an, NULL, 0, -1);
    105  1.1.1.2  mrg 	  return 0;
    106  1.1.1.2  mrg 	}
    107  1.1.1.2  mrg       else if (c > 0)
    108  1.1.1.2  mrg 	{
    109  1.1.1.2  mrg 	  MP_PTR_SWAP (ap, bp);
    110  1.1.1.2  mrg 	  swapped ^= 1;
    111  1.1.1.2  mrg 	}
    112  1.1.1.2  mrg     }
    113  1.1.1.2  mrg   else
    114  1.1.1.2  mrg     {
    115  1.1.1.2  mrg       if (an > bn)
    116  1.1.1.2  mrg 	{
    117  1.1.1.2  mrg 	  MPN_PTR_SWAP (ap, an, bp, bn);
    118  1.1.1.2  mrg 	  swapped ^= 1;
    119  1.1.1.2  mrg 	}
    120  1.1.1.2  mrg     }
    121  1.1.1.2  mrg   if (an <= s)
    122  1.1.1.2  mrg     {
    123  1.1.1.2  mrg       if (s == 0)
    124  1.1.1.2  mrg 	hook (ctx, bp, bn, NULL, 0, swapped ^ 1);
    125  1.1.1.2  mrg       return 0;
    126      1.1  mrg     }
    127      1.1  mrg 
    128  1.1.1.2  mrg   ASSERT_NOCARRY (mpn_sub (bp, bp, bn, ap, an));
    129  1.1.1.2  mrg   MPN_NORMALIZE (bp, bn);
    130  1.1.1.2  mrg   ASSERT (bn > 0);
    131      1.1  mrg 
    132  1.1.1.2  mrg   if (bn <= s)
    133  1.1.1.2  mrg     {
    134  1.1.1.2  mrg       /* Undo subtraction. */
    135  1.1.1.2  mrg       mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
    136  1.1.1.2  mrg       if (cy > 0)
    137  1.1.1.2  mrg 	bp[an] = cy;
    138  1.1.1.2  mrg       return 0;
    139  1.1.1.2  mrg     }
    140  1.1.1.2  mrg 
    141  1.1.1.2  mrg   /* Arrange so that a < b */
    142  1.1.1.2  mrg   if (an == bn)
    143      1.1  mrg     {
    144      1.1  mrg       int c;
    145      1.1  mrg       MPN_CMP (c, ap, bp, an);
    146      1.1  mrg       if (UNLIKELY (c == 0))
    147  1.1.1.2  mrg 	{
    148  1.1.1.2  mrg 	  if (s > 0)
    149  1.1.1.2  mrg 	    /* Just record subtraction and return */
    150  1.1.1.2  mrg 	    hook (ctx, NULL, 0, &one, 1, swapped);
    151  1.1.1.2  mrg 	  else
    152  1.1.1.2  mrg 	    /* Found gcd. */
    153  1.1.1.2  mrg 	    hook (ctx, bp, bn, NULL, 0, swapped);
    154  1.1.1.2  mrg 	  return 0;
    155  1.1.1.2  mrg 	}
    156  1.1.1.2  mrg 
    157  1.1.1.2  mrg       hook (ctx, NULL, 0, &one, 1, swapped);
    158  1.1.1.2  mrg 
    159  1.1.1.2  mrg       if (c > 0)
    160  1.1.1.2  mrg 	{
    161  1.1.1.2  mrg 	  MP_PTR_SWAP (ap, bp);
    162  1.1.1.2  mrg 	  swapped ^= 1;
    163  1.1.1.2  mrg 	}
    164      1.1  mrg     }
    165  1.1.1.2  mrg   else
    166  1.1.1.2  mrg     {
    167  1.1.1.2  mrg       hook (ctx, NULL, 0, &one, 1, swapped);
    168      1.1  mrg 
    169  1.1.1.2  mrg       if (an > bn)
    170  1.1.1.2  mrg 	{
    171  1.1.1.2  mrg 	  MPN_PTR_SWAP (ap, an, bp, bn);
    172  1.1.1.2  mrg 	  swapped ^= 1;
    173  1.1.1.2  mrg 	}
    174  1.1.1.2  mrg     }
    175      1.1  mrg 
    176  1.1.1.2  mrg   mpn_tdiv_qr (tp, bp, 0, bp, bn, ap, an);
    177  1.1.1.2  mrg   qn = bn - an + 1;
    178  1.1.1.2  mrg   bn = an;
    179  1.1.1.2  mrg   MPN_NORMALIZE (bp, bn);
    180  1.1.1.2  mrg 
    181  1.1.1.2  mrg   if (UNLIKELY (bn <= s))
    182  1.1.1.2  mrg     {
    183  1.1.1.2  mrg       if (s == 0)
    184  1.1.1.2  mrg 	{
    185  1.1.1.2  mrg 	  hook (ctx, ap, an, tp, qn, swapped);
    186  1.1.1.2  mrg 	  return 0;
    187  1.1.1.2  mrg 	}
    188  1.1.1.2  mrg 
    189  1.1.1.2  mrg       /* Quotient is one too large, so decrement it and add back A. */
    190  1.1.1.2  mrg       if (bn > 0)
    191  1.1.1.2  mrg 	{
    192  1.1.1.2  mrg 	  mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
    193  1.1.1.2  mrg 	  if (cy)
    194  1.1.1.2  mrg 	    bp[an++] = cy;
    195  1.1.1.2  mrg 	}
    196  1.1.1.2  mrg       else
    197  1.1.1.2  mrg 	MPN_COPY (bp, ap, an);
    198  1.1.1.2  mrg 
    199  1.1.1.2  mrg       MPN_DECR_U (tp, qn, 1);
    200  1.1.1.2  mrg     }
    201      1.1  mrg 
    202  1.1.1.2  mrg   hook (ctx, NULL, 0, tp, qn, swapped);
    203  1.1.1.2  mrg   return an;
    204      1.1  mrg }
    205