xref: /dflybsd-src/contrib/gmp/mpn/generic/gcdext_subdiv_step.c (revision d365564473a20a528d07c59cad8ee2f4bea5546f)
14b6a78b7SSimon Schubert /* gcdext_subdiv_step.c.
24b6a78b7SSimon Schubert 
34b6a78b7SSimon Schubert    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
44b6a78b7SSimon Schubert    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
54b6a78b7SSimon Schubert    GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
64b6a78b7SSimon Schubert 
78b5d8148SSascha Wildner Copyright 2003, 2004, 2005, 2008, 2009 Free Software Foundation, Inc.
84b6a78b7SSimon Schubert 
94b6a78b7SSimon Schubert This file is part of the GNU MP Library.
104b6a78b7SSimon Schubert 
114b6a78b7SSimon Schubert The GNU MP Library is free software; you can redistribute it and/or modify
124b6a78b7SSimon Schubert it under the terms of the GNU Lesser General Public License as published by
134b6a78b7SSimon Schubert the Free Software Foundation; either version 3 of the License, or (at your
144b6a78b7SSimon Schubert option) any later version.
154b6a78b7SSimon Schubert 
164b6a78b7SSimon Schubert The GNU MP Library is distributed in the hope that it will be useful, but
174b6a78b7SSimon Schubert WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
184b6a78b7SSimon Schubert or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
194b6a78b7SSimon Schubert License for more details.
204b6a78b7SSimon Schubert 
214b6a78b7SSimon Schubert You should have received a copy of the GNU Lesser General Public License
224b6a78b7SSimon Schubert along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
234b6a78b7SSimon Schubert 
244b6a78b7SSimon Schubert #include "gmp.h"
254b6a78b7SSimon Schubert #include "gmp-impl.h"
264b6a78b7SSimon Schubert #include "longlong.h"
274b6a78b7SSimon Schubert 
284b6a78b7SSimon Schubert /* Used when mpn_hgcd or mpn_hgcd2 has failed. Then either one of a or
294b6a78b7SSimon Schubert    b is small, or the difference is small. Perform one subtraction
304b6a78b7SSimon Schubert    followed by one division. If the gcd is found, stores it in gp and
314b6a78b7SSimon Schubert    *gn, and returns zero. Otherwise, compute the reduced a and b,
324b6a78b7SSimon Schubert    return the new size, and cofactors. */
334b6a78b7SSimon Schubert 
344b6a78b7SSimon Schubert /* Temporary storage: Needs n limbs for the quotient, at qp. tp must
354b6a78b7SSimon Schubert    point to an area large enough for the resulting cofactor, plus one
364b6a78b7SSimon Schubert    limb extra. All in all, 2N + 1 if N is a bound for both inputs and
374b6a78b7SSimon Schubert    outputs. */
384b6a78b7SSimon Schubert mp_size_t
mpn_gcdext_subdiv_step(mp_ptr gp,mp_size_t * gn,mp_ptr up,mp_size_t * usizep,mp_ptr ap,mp_ptr bp,mp_size_t n,mp_ptr u0,mp_ptr u1,mp_size_t * unp,mp_ptr qp,mp_ptr tp)394b6a78b7SSimon Schubert mpn_gcdext_subdiv_step (mp_ptr gp, mp_size_t *gn, mp_ptr up, mp_size_t *usizep,
404b6a78b7SSimon Schubert 			mp_ptr ap, mp_ptr bp, mp_size_t n,
414b6a78b7SSimon Schubert 			mp_ptr u0, mp_ptr u1, mp_size_t *unp,
424b6a78b7SSimon Schubert 			mp_ptr qp, mp_ptr tp)
434b6a78b7SSimon Schubert {
444b6a78b7SSimon Schubert   mp_size_t an, bn, un;
454b6a78b7SSimon Schubert   mp_size_t qn;
464b6a78b7SSimon Schubert   mp_size_t u0n;
474b6a78b7SSimon Schubert 
484b6a78b7SSimon Schubert   int swapped;
494b6a78b7SSimon Schubert 
504b6a78b7SSimon Schubert   an = bn = n;
514b6a78b7SSimon Schubert 
524b6a78b7SSimon Schubert   ASSERT (an > 0);
534b6a78b7SSimon Schubert   ASSERT (ap[an-1] > 0 || bp[an-1] > 0);
544b6a78b7SSimon Schubert 
554b6a78b7SSimon Schubert   MPN_NORMALIZE (ap, an);
564b6a78b7SSimon Schubert   MPN_NORMALIZE (bp, bn);
574b6a78b7SSimon Schubert 
584b6a78b7SSimon Schubert   un = *unp;
594b6a78b7SSimon Schubert 
604b6a78b7SSimon Schubert   swapped = 0;
614b6a78b7SSimon Schubert 
624b6a78b7SSimon Schubert   if (UNLIKELY (an == 0))
634b6a78b7SSimon Schubert     {
644b6a78b7SSimon Schubert     return_b:
654b6a78b7SSimon Schubert       MPN_COPY (gp, bp, bn);
664b6a78b7SSimon Schubert       *gn = bn;
674b6a78b7SSimon Schubert 
684b6a78b7SSimon Schubert       MPN_NORMALIZE (u0, un);
694b6a78b7SSimon Schubert       MPN_COPY (up, u0, un);
704b6a78b7SSimon Schubert 
714b6a78b7SSimon Schubert       *usizep = swapped ? un : -un;
724b6a78b7SSimon Schubert 
734b6a78b7SSimon Schubert       return 0;
744b6a78b7SSimon Schubert     }
754b6a78b7SSimon Schubert   else if (UNLIKELY (bn == 0))
764b6a78b7SSimon Schubert     {
774b6a78b7SSimon Schubert       MPN_COPY (gp, ap, an);
784b6a78b7SSimon Schubert       *gn = an;
794b6a78b7SSimon Schubert 
804b6a78b7SSimon Schubert       MPN_NORMALIZE (u1, un);
814b6a78b7SSimon Schubert       MPN_COPY (up, u1, un);
824b6a78b7SSimon Schubert 
834b6a78b7SSimon Schubert       *usizep = swapped ? -un : un;
844b6a78b7SSimon Schubert 
854b6a78b7SSimon Schubert       return 0;
864b6a78b7SSimon Schubert     }
874b6a78b7SSimon Schubert 
884b6a78b7SSimon Schubert   /* Arrange so that a > b, subtract an -= bn, and maintain
894b6a78b7SSimon Schubert      normalization. */
904b6a78b7SSimon Schubert   if (an < bn)
914b6a78b7SSimon Schubert     {
924b6a78b7SSimon Schubert       MPN_PTR_SWAP (ap, an, bp, bn);
934b6a78b7SSimon Schubert       MP_PTR_SWAP (u0, u1);
944b6a78b7SSimon Schubert       swapped ^= 1;
954b6a78b7SSimon Schubert     }
964b6a78b7SSimon Schubert   else if (an == bn)
974b6a78b7SSimon Schubert     {
984b6a78b7SSimon Schubert       int c;
994b6a78b7SSimon Schubert       MPN_CMP (c, ap, bp, an);
1004b6a78b7SSimon Schubert       if (UNLIKELY (c == 0))
1018b5d8148SSascha Wildner 	{
1028b5d8148SSascha Wildner 	  MPN_COPY (gp, ap, an);
1038b5d8148SSascha Wildner 	  *gn = an;
1048b5d8148SSascha Wildner 
1058b5d8148SSascha Wildner 	  /* Must return the smallest cofactor, +u1 or -u0 */
1068b5d8148SSascha Wildner 	  MPN_CMP (c, u0, u1, un);
1078b5d8148SSascha Wildner 	  ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
1088b5d8148SSascha Wildner 
1098b5d8148SSascha Wildner 	  if (c < 0)
1108b5d8148SSascha Wildner 	    {
1118b5d8148SSascha Wildner 	      MPN_NORMALIZE (u0, un);
1128b5d8148SSascha Wildner 	      MPN_COPY (up, u0, un);
1138b5d8148SSascha Wildner 	      swapped ^= 1;
1148b5d8148SSascha Wildner 	    }
1158b5d8148SSascha Wildner 	  else
1168b5d8148SSascha Wildner 	    {
1178b5d8148SSascha Wildner 	      MPN_NORMALIZE_NOT_ZERO (u1, un);
1188b5d8148SSascha Wildner 	      MPN_COPY (up, u1, un);
1198b5d8148SSascha Wildner 	    }
1208b5d8148SSascha Wildner 
1218b5d8148SSascha Wildner 	  *usizep = swapped ? -un : un;
1228b5d8148SSascha Wildner 	  return 0;
1238b5d8148SSascha Wildner 	}
1244b6a78b7SSimon Schubert       else if (c < 0)
1254b6a78b7SSimon Schubert 	{
1264b6a78b7SSimon Schubert 	  MP_PTR_SWAP (ap, bp);
1274b6a78b7SSimon Schubert 	  MP_PTR_SWAP (u0, u1);
1284b6a78b7SSimon Schubert 	  swapped ^= 1;
1294b6a78b7SSimon Schubert 	}
1304b6a78b7SSimon Schubert     }
1314b6a78b7SSimon Schubert   /* Reduce a -= b, u1 += u0 */
1324b6a78b7SSimon Schubert   ASSERT_NOCARRY (mpn_sub (ap, ap, an, bp, bn));
1334b6a78b7SSimon Schubert   MPN_NORMALIZE (ap, an);
1344b6a78b7SSimon Schubert   ASSERT (an > 0);
1354b6a78b7SSimon Schubert 
1364b6a78b7SSimon Schubert   u1[un] = mpn_add_n (u1, u1, u0, un);
1374b6a78b7SSimon Schubert   un += (u1[un] > 0);
1384b6a78b7SSimon Schubert 
1394b6a78b7SSimon Schubert   /* Arrange so that a > b, and divide a = q b + r */
1404b6a78b7SSimon Schubert   if (an < bn)
1414b6a78b7SSimon Schubert     {
1424b6a78b7SSimon Schubert       MPN_PTR_SWAP (ap, an, bp, bn);
1434b6a78b7SSimon Schubert       MP_PTR_SWAP (u0, u1);
1444b6a78b7SSimon Schubert       swapped ^= 1;
1454b6a78b7SSimon Schubert     }
1464b6a78b7SSimon Schubert   else if (an == bn)
1474b6a78b7SSimon Schubert     {
1484b6a78b7SSimon Schubert       int c;
1494b6a78b7SSimon Schubert       MPN_CMP (c, ap, bp, an);
1504b6a78b7SSimon Schubert       if (UNLIKELY (c == 0))
1518b5d8148SSascha Wildner 	goto return_b;
1524b6a78b7SSimon Schubert       else if (c < 0)
1534b6a78b7SSimon Schubert 	{
1544b6a78b7SSimon Schubert 	  MP_PTR_SWAP (ap, bp);
1554b6a78b7SSimon Schubert 	  MP_PTR_SWAP (u0, u1);
1564b6a78b7SSimon Schubert 	  swapped ^= 1;
1574b6a78b7SSimon Schubert 	}
1584b6a78b7SSimon Schubert     }
1594b6a78b7SSimon Schubert 
1604b6a78b7SSimon Schubert   /* Reduce a -= q b, u1 += q u0 */
1614b6a78b7SSimon Schubert   qn = an - bn + 1;
1624b6a78b7SSimon Schubert   mpn_tdiv_qr (qp, ap, 0, ap, an, bp, bn);
1634b6a78b7SSimon Schubert 
1644b6a78b7SSimon Schubert   if (mpn_zero_p (ap, bn))
1654b6a78b7SSimon Schubert     goto return_b;
1664b6a78b7SSimon Schubert 
1674b6a78b7SSimon Schubert   n = bn;
1684b6a78b7SSimon Schubert 
1694b6a78b7SSimon Schubert   /* Update u1 += q u0 */
1704b6a78b7SSimon Schubert   u0n = un;
1714b6a78b7SSimon Schubert   MPN_NORMALIZE (u0, u0n);
1724b6a78b7SSimon Schubert 
1734b6a78b7SSimon Schubert   if (u0n > 0)
1744b6a78b7SSimon Schubert     {
1754b6a78b7SSimon Schubert       qn -= (qp[qn - 1] == 0);
1764b6a78b7SSimon Schubert 
1774b6a78b7SSimon Schubert       if (qn > u0n)
1784b6a78b7SSimon Schubert 	mpn_mul (tp, qp, qn, u0, u0n);
1794b6a78b7SSimon Schubert       else
1804b6a78b7SSimon Schubert 	mpn_mul (tp, u0, u0n, qp, qn);
1814b6a78b7SSimon Schubert 
1824b6a78b7SSimon Schubert       if (qn + u0n > un)
1834b6a78b7SSimon Schubert 	{
184*d2d4b659SJohn Marino 	  mp_size_t u1n = un;
1854b6a78b7SSimon Schubert 	  un = qn + u0n;
186*d2d4b659SJohn Marino 	  un -= (tp[un-1] == 0);
187*d2d4b659SJohn Marino 	  u1[un] = mpn_add (u1, tp, un, u1, u1n);
1884b6a78b7SSimon Schubert 	}
1894b6a78b7SSimon Schubert       else
1904b6a78b7SSimon Schubert 	{
1914b6a78b7SSimon Schubert 	  u1[un] = mpn_add (u1, u1, un, tp, qn + u0n);
1924b6a78b7SSimon Schubert 	}
193*d2d4b659SJohn Marino 
194*d2d4b659SJohn Marino       un += (u1[un] > 0);
1954b6a78b7SSimon Schubert     }
1964b6a78b7SSimon Schubert 
1974b6a78b7SSimon Schubert   *unp = un;
1984b6a78b7SSimon Schubert   return n;
1994b6a78b7SSimon Schubert }
200