xref: /dflybsd-src/contrib/gmp/mpn/generic/div_q.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* mpn_div_q -- division for arbitrary size operands.
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino    Contributed to the GNU project by Torbjorn Granlund.
486d7f5d3SJohn Marino 
586d7f5d3SJohn Marino    THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
686d7f5d3SJohn Marino    SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
786d7f5d3SJohn Marino    GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
886d7f5d3SJohn Marino 
986d7f5d3SJohn Marino Copyright 2009, 2010 Free Software Foundation, Inc.
1086d7f5d3SJohn Marino 
1186d7f5d3SJohn Marino This file is part of the GNU MP Library.
1286d7f5d3SJohn Marino 
1386d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
1486d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1586d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1686d7f5d3SJohn Marino option) any later version.
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1986d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2086d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
2186d7f5d3SJohn Marino License for more details.
2286d7f5d3SJohn Marino 
2386d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
2486d7f5d3SJohn Marino along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
2586d7f5d3SJohn Marino 
2686d7f5d3SJohn Marino #include "gmp.h"
2786d7f5d3SJohn Marino #include "gmp-impl.h"
2886d7f5d3SJohn Marino #include "longlong.h"
2986d7f5d3SJohn Marino 
3086d7f5d3SJohn Marino 
3186d7f5d3SJohn Marino /* Compute Q = N/D with truncation.
3286d7f5d3SJohn Marino      N = {np,nn}
3386d7f5d3SJohn Marino      D = {dp,dn}
3486d7f5d3SJohn Marino      Q = {qp,nn-dn+1}
3586d7f5d3SJohn Marino      T = {scratch,nn+1} is scratch space
3686d7f5d3SJohn Marino    N and D are both untouched by the computation.
3786d7f5d3SJohn Marino    N and T may overlap; pass the same space if N is irrelevant after the call,
3886d7f5d3SJohn Marino    but note that tp needs an extra limb.
3986d7f5d3SJohn Marino 
4086d7f5d3SJohn Marino    Operand requirements:
4186d7f5d3SJohn Marino      N >= D > 0
4286d7f5d3SJohn Marino      dp[dn-1] != 0
4386d7f5d3SJohn Marino      No overlap between the N, D, and Q areas.
4486d7f5d3SJohn Marino 
4586d7f5d3SJohn Marino    This division function does not clobber its input operands, since it is
4686d7f5d3SJohn Marino    intended to support average-O(qn) division, and for that to be effective, it
4786d7f5d3SJohn Marino    cannot put requirements on callers to copy a O(nn) operand.
4886d7f5d3SJohn Marino 
4986d7f5d3SJohn Marino    If a caller does not care about the value of {np,nn+1} after calling this
5086d7f5d3SJohn Marino    function, it should pass np also for the scratch argument.  This function
5186d7f5d3SJohn Marino    will then save some time and space by avoiding allocation and copying.
5286d7f5d3SJohn Marino    (FIXME: Is this a good design?  We only really save any copying for
5386d7f5d3SJohn Marino    already-normalised divisors, which should be rare.  It also prevents us from
5486d7f5d3SJohn Marino    reasonably asking for all scratch space we need.)
5586d7f5d3SJohn Marino 
5686d7f5d3SJohn Marino    We write nn-dn+1 limbs for the quotient, but return void.  Why not return
5786d7f5d3SJohn Marino    the most significant quotient limb?  Look at the 4 main code blocks below
5886d7f5d3SJohn Marino    (consisting of an outer if-else where each arm contains an if-else). It is
5986d7f5d3SJohn Marino    tricky for the first code block, since the mpn_*_div_q calls will typically
6086d7f5d3SJohn Marino    generate all nn-dn+1 and return 0 or 1.  I don't see how to fix that unless
6186d7f5d3SJohn Marino    we generate the most significant quotient limb here, before calling
6286d7f5d3SJohn Marino    mpn_*_div_q, or put the quotient in a temporary area.  Since this is a
6386d7f5d3SJohn Marino    critical division case (the SB sub-case in particular) copying is not a good
6486d7f5d3SJohn Marino    idea.
6586d7f5d3SJohn Marino 
6686d7f5d3SJohn Marino    It might make sense to split the if-else parts of the (qn + FUDGE
6786d7f5d3SJohn Marino    >= dn) blocks into separate functions, since we could promise quite
6886d7f5d3SJohn Marino    different things to callers in these two cases.  The 'then' case
6986d7f5d3SJohn Marino    benefits from np=scratch, and it could perhaps even tolerate qp=np,
7086d7f5d3SJohn Marino    saving some headache for many callers.
7186d7f5d3SJohn Marino 
7286d7f5d3SJohn Marino    FIXME: Scratch allocation leaves a lot to be desired.  E.g., for the MU size
7386d7f5d3SJohn Marino    operands, we do not reuse the huge scratch for adjustments.  This can be a
7486d7f5d3SJohn Marino    serious waste of memory for the largest operands.
7586d7f5d3SJohn Marino */
7686d7f5d3SJohn Marino 
7786d7f5d3SJohn Marino /* FUDGE determines when to try getting an approximate quotient from the upper
7886d7f5d3SJohn Marino    parts of the dividend and divisor, then adjust.  N.B. FUDGE must be >= 2
7986d7f5d3SJohn Marino    for the code to be correct.  */
8086d7f5d3SJohn Marino #define FUDGE 5			/* FIXME: tune this */
8186d7f5d3SJohn Marino 
8286d7f5d3SJohn Marino #define DC_DIV_Q_THRESHOLD      DC_DIVAPPR_Q_THRESHOLD
8386d7f5d3SJohn Marino #define MU_DIV_Q_THRESHOLD      MU_DIVAPPR_Q_THRESHOLD
8486d7f5d3SJohn Marino #define MUPI_DIV_Q_THRESHOLD  MUPI_DIVAPPR_Q_THRESHOLD
8586d7f5d3SJohn Marino #ifndef MUPI_DIVAPPR_Q_THRESHOLD
8686d7f5d3SJohn Marino #define MUPI_DIVAPPR_Q_THRESHOLD  MUPI_DIV_QR_THRESHOLD
8786d7f5d3SJohn Marino #endif
8886d7f5d3SJohn Marino 
8986d7f5d3SJohn Marino void
mpn_div_q(mp_ptr qp,mp_srcptr np,mp_size_t nn,mp_srcptr dp,mp_size_t dn,mp_ptr scratch)9086d7f5d3SJohn Marino mpn_div_q (mp_ptr qp,
9186d7f5d3SJohn Marino 	   mp_srcptr np, mp_size_t nn,
9286d7f5d3SJohn Marino 	   mp_srcptr dp, mp_size_t dn, mp_ptr scratch)
9386d7f5d3SJohn Marino {
9486d7f5d3SJohn Marino   mp_ptr new_dp, new_np, tp, rp;
9586d7f5d3SJohn Marino   mp_limb_t cy, dh, qh;
9686d7f5d3SJohn Marino   mp_size_t new_nn, qn;
9786d7f5d3SJohn Marino   gmp_pi1_t dinv;
9886d7f5d3SJohn Marino   int cnt;
9986d7f5d3SJohn Marino   TMP_DECL;
10086d7f5d3SJohn Marino   TMP_MARK;
10186d7f5d3SJohn Marino 
10286d7f5d3SJohn Marino   ASSERT (nn >= dn);
10386d7f5d3SJohn Marino   ASSERT (dn > 0);
10486d7f5d3SJohn Marino   ASSERT (dp[dn - 1] != 0);
10586d7f5d3SJohn Marino   ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1, np, nn));
10686d7f5d3SJohn Marino   ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1, dp, dn));
10786d7f5d3SJohn Marino   ASSERT (MPN_SAME_OR_SEPARATE_P (np, scratch, nn));
10886d7f5d3SJohn Marino 
10986d7f5d3SJohn Marino   ASSERT_ALWAYS (FUDGE >= 2);
11086d7f5d3SJohn Marino 
11186d7f5d3SJohn Marino   if (dn == 1)
11286d7f5d3SJohn Marino     {
11386d7f5d3SJohn Marino       mpn_divrem_1 (qp, 0L, np, nn, dp[dn - 1]);
11486d7f5d3SJohn Marino       return;
11586d7f5d3SJohn Marino     }
11686d7f5d3SJohn Marino 
11786d7f5d3SJohn Marino   qn = nn - dn + 1;		/* Quotient size, high limb might be zero */
11886d7f5d3SJohn Marino 
11986d7f5d3SJohn Marino   if (qn + FUDGE >= dn)
12086d7f5d3SJohn Marino     {
12186d7f5d3SJohn Marino       /* |________________________|
12286d7f5d3SJohn Marino                           |_______|  */
12386d7f5d3SJohn Marino       new_np = scratch;
12486d7f5d3SJohn Marino 
12586d7f5d3SJohn Marino       dh = dp[dn - 1];
12686d7f5d3SJohn Marino       if (LIKELY ((dh & GMP_NUMB_HIGHBIT) == 0))
12786d7f5d3SJohn Marino 	{
12886d7f5d3SJohn Marino 	  count_leading_zeros (cnt, dh);
12986d7f5d3SJohn Marino 
13086d7f5d3SJohn Marino 	  cy = mpn_lshift (new_np, np, nn, cnt);
13186d7f5d3SJohn Marino 	  new_np[nn] = cy;
13286d7f5d3SJohn Marino 	  new_nn = nn + (cy != 0);
13386d7f5d3SJohn Marino 
13486d7f5d3SJohn Marino 	  new_dp = TMP_ALLOC_LIMBS (dn);
13586d7f5d3SJohn Marino 	  mpn_lshift (new_dp, dp, dn, cnt);
13686d7f5d3SJohn Marino 
13786d7f5d3SJohn Marino 	  if (dn == 2)
13886d7f5d3SJohn Marino 	    {
13986d7f5d3SJohn Marino 	      qh = mpn_divrem_2 (qp, 0L, new_np, new_nn, new_dp);
14086d7f5d3SJohn Marino 	    }
14186d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (dn, DC_DIV_Q_THRESHOLD) ||
14286d7f5d3SJohn Marino 		   BELOW_THRESHOLD (new_nn - dn, DC_DIV_Q_THRESHOLD))
14386d7f5d3SJohn Marino 	    {
14486d7f5d3SJohn Marino 	      invert_pi1 (dinv, new_dp[dn - 1], new_dp[dn - 2]);
14586d7f5d3SJohn Marino 	      qh = mpn_sbpi1_div_q (qp, new_np, new_nn, new_dp, dn, dinv.inv32);
14686d7f5d3SJohn Marino 	    }
14786d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (dn, MUPI_DIV_Q_THRESHOLD) ||   /* fast condition */
14886d7f5d3SJohn Marino 		   BELOW_THRESHOLD (nn, 2 * MU_DIV_Q_THRESHOLD) || /* fast condition */
14986d7f5d3SJohn Marino 		   (double) (2 * (MU_DIV_Q_THRESHOLD - MUPI_DIV_Q_THRESHOLD)) * dn /* slow... */
15086d7f5d3SJohn Marino 		   + (double) MUPI_DIV_Q_THRESHOLD * nn > (double) dn * nn)   /* ...condition */
15186d7f5d3SJohn Marino 	    {
15286d7f5d3SJohn Marino 	      invert_pi1 (dinv, new_dp[dn - 1], new_dp[dn - 2]);
15386d7f5d3SJohn Marino 	      qh = mpn_dcpi1_div_q (qp, new_np, new_nn, new_dp, dn, &dinv);
15486d7f5d3SJohn Marino 	    }
15586d7f5d3SJohn Marino 	  else
15686d7f5d3SJohn Marino 	    {
15786d7f5d3SJohn Marino 	      mp_size_t itch = mpn_mu_div_q_itch (new_nn, dn, 0);
15886d7f5d3SJohn Marino 	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
15986d7f5d3SJohn Marino 	      qh = mpn_mu_div_q (qp, new_np, new_nn, new_dp, dn, scratch);
16086d7f5d3SJohn Marino 	    }
16186d7f5d3SJohn Marino 	  if (cy == 0)
16286d7f5d3SJohn Marino 	    qp[qn - 1] = qh;
16386d7f5d3SJohn Marino 	  else if (UNLIKELY (qh != 0))
16486d7f5d3SJohn Marino 	    {
16586d7f5d3SJohn Marino 	      /* This happens only when the quotient is close to B^n and
16686d7f5d3SJohn Marino 		 mpn_*_divappr_q returned B^n.  */
16786d7f5d3SJohn Marino 	      mp_size_t i, n;
16886d7f5d3SJohn Marino 	      n = new_nn - dn;
16986d7f5d3SJohn Marino 	      for (i = 0; i < n; i++)
17086d7f5d3SJohn Marino 		qp[i] = GMP_NUMB_MAX;
17186d7f5d3SJohn Marino 	      qh = 0;		/* currently ignored */
17286d7f5d3SJohn Marino 	    }
17386d7f5d3SJohn Marino 	}
17486d7f5d3SJohn Marino       else  /* divisor is already normalised */
17586d7f5d3SJohn Marino 	{
17686d7f5d3SJohn Marino 	  if (new_np != np)
17786d7f5d3SJohn Marino 	    MPN_COPY (new_np, np, nn);
17886d7f5d3SJohn Marino 
17986d7f5d3SJohn Marino 	  if (dn == 2)
18086d7f5d3SJohn Marino 	    {
18186d7f5d3SJohn Marino 	      qh = mpn_divrem_2 (qp, 0L, new_np, nn, dp);
18286d7f5d3SJohn Marino 	    }
18386d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (dn, DC_DIV_Q_THRESHOLD) ||
18486d7f5d3SJohn Marino 		   BELOW_THRESHOLD (nn - dn, DC_DIV_Q_THRESHOLD))
18586d7f5d3SJohn Marino 	    {
18686d7f5d3SJohn Marino 	      invert_pi1 (dinv, dh, dp[dn - 2]);
18786d7f5d3SJohn Marino 	      qh = mpn_sbpi1_div_q (qp, new_np, nn, dp, dn, dinv.inv32);
18886d7f5d3SJohn Marino 	    }
18986d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (dn, MUPI_DIV_Q_THRESHOLD) ||   /* fast condition */
19086d7f5d3SJohn Marino 		   BELOW_THRESHOLD (nn, 2 * MU_DIV_Q_THRESHOLD) || /* fast condition */
19186d7f5d3SJohn Marino 		   (double) (2 * (MU_DIV_Q_THRESHOLD - MUPI_DIV_Q_THRESHOLD)) * dn /* slow... */
19286d7f5d3SJohn Marino 		   + (double) MUPI_DIV_Q_THRESHOLD * nn > (double) dn * nn)   /* ...condition */
19386d7f5d3SJohn Marino 	    {
19486d7f5d3SJohn Marino 	      invert_pi1 (dinv, dh, dp[dn - 2]);
19586d7f5d3SJohn Marino 	      qh = mpn_dcpi1_div_q (qp, new_np, nn, dp, dn, &dinv);
19686d7f5d3SJohn Marino 	    }
19786d7f5d3SJohn Marino 	  else
19886d7f5d3SJohn Marino 	    {
19986d7f5d3SJohn Marino 	      mp_size_t itch = mpn_mu_div_q_itch (nn, dn, 0);
20086d7f5d3SJohn Marino 	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
20186d7f5d3SJohn Marino 	      qh = mpn_mu_div_q (qp, np, nn, dp, dn, scratch);
20286d7f5d3SJohn Marino 	    }
20386d7f5d3SJohn Marino 	  qp[nn - dn] = qh;
20486d7f5d3SJohn Marino 	}
20586d7f5d3SJohn Marino     }
20686d7f5d3SJohn Marino   else
20786d7f5d3SJohn Marino     {
20886d7f5d3SJohn Marino       /* |________________________|
20986d7f5d3SJohn Marino                 |_________________|  */
21086d7f5d3SJohn Marino       tp = TMP_ALLOC_LIMBS (qn + 1);
21186d7f5d3SJohn Marino 
21286d7f5d3SJohn Marino       new_np = scratch;
21386d7f5d3SJohn Marino       new_nn = 2 * qn + 1;
21486d7f5d3SJohn Marino       if (new_np == np)
21586d7f5d3SJohn Marino 	/* We need {np,nn} to remain untouched until the final adjustment, so
21686d7f5d3SJohn Marino 	   we need to allocate separate space for new_np.  */
21786d7f5d3SJohn Marino 	new_np = TMP_ALLOC_LIMBS (new_nn + 1);
21886d7f5d3SJohn Marino 
21986d7f5d3SJohn Marino 
22086d7f5d3SJohn Marino       dh = dp[dn - 1];
22186d7f5d3SJohn Marino       if (LIKELY ((dh & GMP_NUMB_HIGHBIT) == 0))
22286d7f5d3SJohn Marino 	{
22386d7f5d3SJohn Marino 	  count_leading_zeros (cnt, dh);
22486d7f5d3SJohn Marino 
22586d7f5d3SJohn Marino 	  cy = mpn_lshift (new_np, np + nn - new_nn, new_nn, cnt);
22686d7f5d3SJohn Marino 	  new_np[new_nn] = cy;
22786d7f5d3SJohn Marino 
22886d7f5d3SJohn Marino 	  new_nn += (cy != 0);
22986d7f5d3SJohn Marino 
23086d7f5d3SJohn Marino 	  new_dp = TMP_ALLOC_LIMBS (qn + 1);
23186d7f5d3SJohn Marino 	  mpn_lshift (new_dp, dp + dn - (qn + 1), qn + 1, cnt);
23286d7f5d3SJohn Marino 	  new_dp[0] |= dp[dn - (qn + 1) - 1] >> (GMP_NUMB_BITS - cnt);
23386d7f5d3SJohn Marino 
23486d7f5d3SJohn Marino 	  if (qn + 1 == 2)
23586d7f5d3SJohn Marino 	    {
23686d7f5d3SJohn Marino 	      qh = mpn_divrem_2 (tp, 0L, new_np, new_nn, new_dp);
23786d7f5d3SJohn Marino 	    }
23886d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD - 1))
23986d7f5d3SJohn Marino 	    {
24086d7f5d3SJohn Marino 	      invert_pi1 (dinv, new_dp[qn], new_dp[qn - 1]);
24186d7f5d3SJohn Marino 	      qh = mpn_sbpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, dinv.inv32);
24286d7f5d3SJohn Marino 	    }
24386d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (qn, MU_DIVAPPR_Q_THRESHOLD - 1))
24486d7f5d3SJohn Marino 	    {
24586d7f5d3SJohn Marino 	      invert_pi1 (dinv, new_dp[qn], new_dp[qn - 1]);
24686d7f5d3SJohn Marino 	      qh = mpn_dcpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, &dinv);
24786d7f5d3SJohn Marino 	    }
24886d7f5d3SJohn Marino 	  else
24986d7f5d3SJohn Marino 	    {
25086d7f5d3SJohn Marino 	      mp_size_t itch = mpn_mu_divappr_q_itch (new_nn, qn + 1, 0);
25186d7f5d3SJohn Marino 	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
25286d7f5d3SJohn Marino 	      qh = mpn_mu_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, scratch);
25386d7f5d3SJohn Marino 	    }
25486d7f5d3SJohn Marino 	  if (cy == 0)
25586d7f5d3SJohn Marino 	    tp[qn] = qh;
25686d7f5d3SJohn Marino 	  else if (UNLIKELY (qh != 0))
25786d7f5d3SJohn Marino 	    {
25886d7f5d3SJohn Marino 	      /* This happens only when the quotient is close to B^n and
25986d7f5d3SJohn Marino 		 mpn_*_divappr_q returned B^n.  */
26086d7f5d3SJohn Marino 	      mp_size_t i, n;
26186d7f5d3SJohn Marino 	      n = new_nn - (qn + 1);
26286d7f5d3SJohn Marino 	      for (i = 0; i < n; i++)
26386d7f5d3SJohn Marino 		tp[i] = GMP_NUMB_MAX;
26486d7f5d3SJohn Marino 	      qh = 0;		/* currently ignored */
26586d7f5d3SJohn Marino 	    }
26686d7f5d3SJohn Marino 	}
26786d7f5d3SJohn Marino       else  /* divisor is already normalised */
26886d7f5d3SJohn Marino 	{
26986d7f5d3SJohn Marino 	  MPN_COPY (new_np, np + nn - new_nn, new_nn); /* pointless of MU will be used */
27086d7f5d3SJohn Marino 
27186d7f5d3SJohn Marino 	  new_dp = (mp_ptr) dp + dn - (qn + 1);
27286d7f5d3SJohn Marino 
27386d7f5d3SJohn Marino 	  if (qn == 2 - 1)
27486d7f5d3SJohn Marino 	    {
27586d7f5d3SJohn Marino 	      qh = mpn_divrem_2 (tp, 0L, new_np, new_nn, new_dp);
27686d7f5d3SJohn Marino 	    }
27786d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD - 1))
27886d7f5d3SJohn Marino 	    {
27986d7f5d3SJohn Marino 	      invert_pi1 (dinv, dh, new_dp[qn - 1]);
28086d7f5d3SJohn Marino 	      qh = mpn_sbpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, dinv.inv32);
28186d7f5d3SJohn Marino 	    }
28286d7f5d3SJohn Marino 	  else if (BELOW_THRESHOLD (qn, MU_DIVAPPR_Q_THRESHOLD - 1))
28386d7f5d3SJohn Marino 	    {
28486d7f5d3SJohn Marino 	      invert_pi1 (dinv, dh, new_dp[qn - 1]);
28586d7f5d3SJohn Marino 	      qh = mpn_dcpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, &dinv);
28686d7f5d3SJohn Marino 	    }
28786d7f5d3SJohn Marino 	  else
28886d7f5d3SJohn Marino 	    {
28986d7f5d3SJohn Marino 	      mp_size_t itch = mpn_mu_divappr_q_itch (new_nn, qn + 1, 0);
29086d7f5d3SJohn Marino 	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
29186d7f5d3SJohn Marino 	      qh = mpn_mu_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, scratch);
29286d7f5d3SJohn Marino 	    }
29386d7f5d3SJohn Marino 	  tp[qn] = qh;
29486d7f5d3SJohn Marino 	}
29586d7f5d3SJohn Marino 
29686d7f5d3SJohn Marino       MPN_COPY (qp, tp + 1, qn);
29786d7f5d3SJohn Marino       if (tp[0] <= 4)
29886d7f5d3SJohn Marino         {
29986d7f5d3SJohn Marino 	  mp_size_t rn;
30086d7f5d3SJohn Marino 
30186d7f5d3SJohn Marino           rp = TMP_ALLOC_LIMBS (dn + qn);
30286d7f5d3SJohn Marino           mpn_mul (rp, dp, dn, tp + 1, qn);
30386d7f5d3SJohn Marino 	  rn = dn + qn;
30486d7f5d3SJohn Marino 	  rn -= rp[rn - 1] == 0;
30586d7f5d3SJohn Marino 
30686d7f5d3SJohn Marino           if (rn > nn || mpn_cmp (np, rp, nn) < 0)
30786d7f5d3SJohn Marino             mpn_decr_u (qp, 1);
30886d7f5d3SJohn Marino         }
30986d7f5d3SJohn Marino     }
31086d7f5d3SJohn Marino 
31186d7f5d3SJohn Marino   TMP_FREE;
31286d7f5d3SJohn Marino }
313