Home | History | Annotate | Line # | Download | only in generic
      1      1.1  mrg /* mpn_mu_div_q.
      2      1.1  mrg 
      3      1.1  mrg    Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
      4      1.1  mrg 
      5      1.1  mrg    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
      6      1.1  mrg    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
      7      1.1  mrg    GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
      8      1.1  mrg 
      9  1.1.1.2  mrg Copyright 2005-2007, 2009, 2010, 2013 Free Software Foundation, Inc.
     10      1.1  mrg 
     11      1.1  mrg This file is part of the GNU MP Library.
     12      1.1  mrg 
     13      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
     14  1.1.1.2  mrg it under the terms of either:
     15  1.1.1.2  mrg 
     16  1.1.1.2  mrg   * the GNU Lesser General Public License as published by the Free
     17  1.1.1.2  mrg     Software Foundation; either version 3 of the License, or (at your
     18  1.1.1.2  mrg     option) any later version.
     19  1.1.1.2  mrg 
     20  1.1.1.2  mrg or
     21  1.1.1.2  mrg 
     22  1.1.1.2  mrg   * the GNU General Public License as published by the Free Software
     23  1.1.1.2  mrg     Foundation; either version 2 of the License, or (at your option) any
     24  1.1.1.2  mrg     later version.
     25  1.1.1.2  mrg 
     26  1.1.1.2  mrg or both in parallel, as here.
     27      1.1  mrg 
     28      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     29      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     30  1.1.1.2  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     31  1.1.1.2  mrg for more details.
     32      1.1  mrg 
     33  1.1.1.2  mrg You should have received copies of the GNU General Public License and the
     34  1.1.1.2  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     35  1.1.1.2  mrg see https://www.gnu.org/licenses/.  */
     36      1.1  mrg 
     37      1.1  mrg 
     38      1.1  mrg /*
     39      1.1  mrg    The idea of the algorithm used herein is to compute a smaller inverted value
     40      1.1  mrg    than used in the standard Barrett algorithm, and thus save time in the
     41      1.1  mrg    Newton iterations, and pay just a small price when using the inverted value
     42      1.1  mrg    for developing quotient bits.  This algorithm was presented at ICMS 2006.
     43      1.1  mrg */
     44      1.1  mrg 
     45      1.1  mrg /*
     46      1.1  mrg   Things to work on:
     47      1.1  mrg 
     48      1.1  mrg   1. This is a rudimentary implementation of mpn_mu_div_q.  The algorithm is
     49      1.1  mrg      probably close to optimal, except when mpn_mu_divappr_q fails.
     50      1.1  mrg 
     51      1.1  mrg   2. We used to fall back to mpn_mu_div_qr when we detect a possible
     52      1.1  mrg      mpn_mu_divappr_q rounding problem, now we multiply and compare.
     53      1.1  mrg      Unfortunately, since mpn_mu_divappr_q does not return the partial
     54      1.1  mrg      remainder, this also doesn't become optimal.  A mpn_mu_divappr_qr could
     55      1.1  mrg      solve that.
     56      1.1  mrg 
     57      1.1  mrg   3. The allocations done here should be made from the scratch area, which
     58      1.1  mrg      then would need to be amended.
     59      1.1  mrg */
     60      1.1  mrg 
     61      1.1  mrg #include <stdlib.h>		/* for NULL */
     62      1.1  mrg #include "gmp-impl.h"
     63      1.1  mrg 
     64      1.1  mrg 
     65      1.1  mrg mp_limb_t
     66      1.1  mrg mpn_mu_div_q (mp_ptr qp,
     67      1.1  mrg 	      mp_srcptr np, mp_size_t nn,
     68      1.1  mrg 	      mp_srcptr dp, mp_size_t dn,
     69      1.1  mrg 	      mp_ptr scratch)
     70      1.1  mrg {
     71  1.1.1.2  mrg   mp_ptr tp, rp;
     72  1.1.1.2  mrg   mp_size_t qn;
     73      1.1  mrg   mp_limb_t cy, qh;
     74      1.1  mrg   TMP_DECL;
     75      1.1  mrg 
     76      1.1  mrg   TMP_MARK;
     77      1.1  mrg 
     78      1.1  mrg   qn = nn - dn;
     79      1.1  mrg 
     80      1.1  mrg   tp = TMP_BALLOC_LIMBS (qn + 1);
     81      1.1  mrg 
     82      1.1  mrg   if (qn >= dn)			/* nn >= 2*dn + 1 */
     83      1.1  mrg     {
     84      1.1  mrg        /* |_______________________|   dividend
     85      1.1  mrg 			 |________|   divisor  */
     86      1.1  mrg 
     87  1.1.1.2  mrg       rp = TMP_BALLOC_LIMBS (nn + 1);
     88  1.1.1.2  mrg       MPN_COPY (rp + 1, np, nn);
     89      1.1  mrg       rp[0] = 0;
     90  1.1.1.2  mrg 
     91  1.1.1.2  mrg       qh = mpn_cmp (rp + 1 + nn - dn, dp, dn) >= 0;
     92  1.1.1.2  mrg       if (qh != 0)
     93  1.1.1.2  mrg 	mpn_sub_n (rp + 1 + nn - dn, rp + 1 + nn - dn, dp, dn);
     94  1.1.1.2  mrg 
     95  1.1.1.2  mrg       cy = mpn_mu_divappr_q (tp, rp, nn + 1, dp, dn, scratch);
     96      1.1  mrg 
     97      1.1  mrg       if (UNLIKELY (cy != 0))
     98      1.1  mrg 	{
     99      1.1  mrg 	  /* Since the partial remainder fed to mpn_preinv_mu_divappr_q was
    100      1.1  mrg 	     canonically reduced, replace the returned value of B^(qn-dn)+eps
    101      1.1  mrg 	     by the largest possible value.  */
    102      1.1  mrg 	  mp_size_t i;
    103  1.1.1.2  mrg 	  for (i = 0; i < qn + 1; i++)
    104      1.1  mrg 	    tp[i] = GMP_NUMB_MAX;
    105      1.1  mrg 	}
    106      1.1  mrg 
    107      1.1  mrg       /* The max error of mpn_mu_divappr_q is +4.  If the low quotient limb is
    108  1.1.1.2  mrg 	 smaller than the max error, we cannot trust the quotient.  */
    109      1.1  mrg       if (tp[0] > 4)
    110      1.1  mrg 	{
    111      1.1  mrg 	  MPN_COPY (qp, tp + 1, qn);
    112      1.1  mrg 	}
    113      1.1  mrg       else
    114      1.1  mrg 	{
    115      1.1  mrg 	  mp_limb_t cy;
    116      1.1  mrg 	  mp_ptr pp;
    117      1.1  mrg 
    118  1.1.1.2  mrg 	  pp = rp;
    119      1.1  mrg 	  mpn_mul (pp, tp + 1, qn, dp, dn);
    120      1.1  mrg 
    121      1.1  mrg 	  cy = (qh != 0) ? mpn_add_n (pp + qn, pp + qn, dp, dn) : 0;
    122      1.1  mrg 
    123      1.1  mrg 	  if (cy || mpn_cmp (pp, np, nn) > 0) /* At most is wrong by one, no cycle. */
    124      1.1  mrg 	    qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
    125      1.1  mrg 	  else /* Same as above */
    126      1.1  mrg 	    MPN_COPY (qp, tp + 1, qn);
    127      1.1  mrg 	}
    128      1.1  mrg     }
    129      1.1  mrg   else
    130      1.1  mrg     {
    131      1.1  mrg        /* |_______________________|   dividend
    132      1.1  mrg 		 |________________|   divisor  */
    133      1.1  mrg 
    134      1.1  mrg       /* FIXME: When nn = 2dn-1, qn becomes dn-1, and the numerator size passed
    135      1.1  mrg 	 here becomes 2dn, i.e., more than nn.  This shouldn't hurt, since only
    136      1.1  mrg 	 the most significant dn-1 limbs will actually be read, but it is not
    137      1.1  mrg 	 pretty.  */
    138      1.1  mrg 
    139      1.1  mrg       qh = mpn_mu_divappr_q (tp, np + nn - (2 * qn + 2), 2 * qn + 2,
    140      1.1  mrg 			     dp + dn - (qn + 1), qn + 1, scratch);
    141      1.1  mrg 
    142      1.1  mrg       /* The max error of mpn_mu_divappr_q is +4, but we get an additional
    143      1.1  mrg          error from the divisor truncation.  */
    144      1.1  mrg       if (tp[0] > 6)
    145      1.1  mrg 	{
    146      1.1  mrg 	  MPN_COPY (qp, tp + 1, qn);
    147      1.1  mrg 	}
    148      1.1  mrg       else
    149      1.1  mrg 	{
    150      1.1  mrg 	  mp_limb_t cy;
    151      1.1  mrg 
    152      1.1  mrg 	  /* FIXME: a shorter product should be enough; we may use already
    153      1.1  mrg 	     allocated space... */
    154      1.1  mrg 	  rp = TMP_BALLOC_LIMBS (nn);
    155      1.1  mrg 	  mpn_mul (rp, dp, dn, tp + 1, qn);
    156      1.1  mrg 
    157      1.1  mrg 	  cy = (qh != 0) ? mpn_add_n (rp + qn, rp + qn, dp, dn) : 0;
    158      1.1  mrg 
    159      1.1  mrg 	  if (cy || mpn_cmp (rp, np, nn) > 0) /* At most is wrong by one, no cycle. */
    160      1.1  mrg 	    qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
    161      1.1  mrg 	  else /* Same as above */
    162      1.1  mrg 	    MPN_COPY (qp, tp + 1, qn);
    163      1.1  mrg 	}
    164      1.1  mrg     }
    165      1.1  mrg 
    166      1.1  mrg   TMP_FREE;
    167      1.1  mrg   return qh;
    168      1.1  mrg }
    169      1.1  mrg 
    170      1.1  mrg mp_size_t
    171      1.1  mrg mpn_mu_div_q_itch (mp_size_t nn, mp_size_t dn, int mua_k)
    172      1.1  mrg {
    173  1.1.1.2  mrg   mp_size_t qn;
    174      1.1  mrg 
    175      1.1  mrg   qn = nn - dn;
    176      1.1  mrg   if (qn >= dn)
    177      1.1  mrg     {
    178  1.1.1.2  mrg       return mpn_mu_divappr_q_itch (nn + 1, dn, mua_k);
    179      1.1  mrg     }
    180      1.1  mrg   else
    181      1.1  mrg     {
    182  1.1.1.2  mrg       return mpn_mu_divappr_q_itch (2 * qn + 2, qn + 1, mua_k);
    183      1.1  mrg     }
    184      1.1  mrg }
    185