(root)/
gmp-6.3.0/
mpn/
generic/
remove.c
       1  /* mpn_remove -- divide out all multiples of odd mpn number from another mpn
       2     number.
       3  
       4     Contributed to the GNU project by Torbjorn Granlund.
       5  
       6     THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
       7     SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
       8     GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
       9  
      10  Copyright 2009, 2012-2014, 2017 Free Software Foundation, Inc.
      11  
      12  This file is part of the GNU MP Library.
      13  
      14  The GNU MP Library is free software; you can redistribute it and/or modify
      15  it under the terms of either:
      16  
      17    * the GNU Lesser General Public License as published by the Free
      18      Software Foundation; either version 3 of the License, or (at your
      19      option) any later version.
      20  
      21  or
      22  
      23    * the GNU General Public License as published by the Free Software
      24      Foundation; either version 2 of the License, or (at your option) any
      25      later version.
      26  
      27  or both in parallel, as here.
      28  
      29  The GNU MP Library is distributed in the hope that it will be useful, but
      30  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      31  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      32  for more details.
      33  
      34  You should have received copies of the GNU General Public License and the
      35  GNU Lesser General Public License along with the GNU MP Library.  If not,
      36  see https://www.gnu.org/licenses/.  */
      37  
      38  #include "gmp-impl.h"
      39  
      40  #if GMP_LIMB_BITS > 50
      41  #define LOG 50
      42  #else
      43  #define LOG GMP_LIMB_BITS
      44  #endif
      45  
      46  
      47  /* Input: U = {up,un}, V = {vp,vn} must be odd, cap
      48     Ouput  W = {wp,*wn} allocation need is exactly *wn
      49  
      50     Set W = U / V^k, where k is the largest integer <= cap such that the
      51     division yields an integer.
      52  
      53     FIXME: We currently allow any operand overlap.  This is quite non mpn-ish
      54     and might be changed, since it cost significant temporary space.
      55     * If we require W to have space for un + 1 limbs, we could save qp or qp2
      56       (but we will still need to copy things into wp 50% of the time).
      57     * If we allow ourselves to clobber U, we could save the other of qp and qp2,
      58       and the initial COPY (but also here we would need un + 1 limbs).
      59  */
      60  
      61  /* FIXME: We need to wrap mpn_bdiv_qr due to the itch interface.  This need
      62     indicates a flaw in the current itch mechanism: Which operands not greater
      63     than un,un will incur the worst itch?  We need a parallel foo_maxitch set
      64     of functions.  */
      65  static void
      66  mpn_bdiv_qr_wrap (mp_ptr qp, mp_ptr rp,
      67  		  mp_srcptr np, mp_size_t nn,
      68  		  mp_srcptr dp, mp_size_t dn)
      69  {
      70    mp_ptr scratch_out;
      71    TMP_DECL;
      72  
      73    TMP_MARK;
      74    scratch_out = TMP_ALLOC_LIMBS (mpn_bdiv_qr_itch (nn, dn));
      75    mpn_bdiv_qr (qp, rp, np, nn, dp, dn, scratch_out);
      76  
      77    TMP_FREE;
      78  }
      79  
      80  mp_bitcnt_t
      81  mpn_remove (mp_ptr wp, mp_size_t *wn,
      82  	    mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn,
      83  	    mp_bitcnt_t cap)
      84  {
      85    mp_srcptr pwpsp[LOG];
      86    mp_size_t pwpsn[LOG];
      87    mp_size_t npowers;
      88    mp_ptr tp, qp, np, qp2;
      89    mp_srcptr pp;
      90    mp_size_t pn, nn, qn, i;
      91    mp_bitcnt_t pwr;
      92    TMP_DECL;
      93  
      94    ASSERT (un > 0);
      95    ASSERT (vn > 0);
      96    ASSERT (vp[0] % 2 != 0);	/* 2-adic division wants odd numbers */
      97    ASSERT (vn > 1 || vp[0] > 1);	/* else we would loop indefinitely */
      98  
      99    TMP_MARK;
     100  
     101    TMP_ALLOC_LIMBS_3 (qp, un + 1,	/* quotient, alternating */
     102  		     qp2, un + 1,	/* quotient, alternating */
     103  		     tp, (un + 1 + vn) / 2); /* remainder */
     104    pp = vp;
     105    pn = vn;
     106  
     107    MPN_COPY (qp, up, un);
     108    qn = un;
     109  
     110    npowers = 0;
     111    while (qn >= pn)
     112      {
     113        qp[qn] = 0;
     114        mpn_bdiv_qr_wrap (qp2, tp, qp, qn + 1, pp, pn);
     115        if (!mpn_zero_p (tp, pn))
     116  	{
     117  	  if (mpn_cmp (tp, pp, pn) != 0)
     118  	    break;		/* could not divide by V^npowers */
     119  	}
     120  
     121        MP_PTR_SWAP (qp, qp2);
     122        qn = qn - pn;
     123        mpn_neg (qp, qp, qn+1);
     124  
     125        qn += qp[qn] != 0;
     126  
     127        pwpsp[npowers] = pp;
     128        pwpsn[npowers] = pn;
     129        ++npowers;
     130  
     131        if (((mp_bitcnt_t) 2 << npowers) - 1 > cap)
     132  	break;
     133  
     134        nn = 2 * pn - 1;		/* next power will be at least this large */
     135        if (nn > qn)
     136  	break;			/* next power would be overlarge */
     137  
     138        if (npowers == 1)		/* Alloc once, but only if it's needed */
     139  	np = TMP_ALLOC_LIMBS (qn + LOG);	/* powers of V */
     140        else
     141  	np += pn;
     142  
     143        mpn_sqr (np, pp, pn);
     144        pn = nn + (np[nn] != 0);
     145        pp = np;
     146      }
     147  
     148    pwr = ((mp_bitcnt_t) 1 << npowers) - 1;
     149  
     150    for (i = npowers; --i >= 0;)
     151      {
     152        pn = pwpsn[i];
     153        if (qn < pn)
     154  	continue;
     155  
     156        if (pwr + ((mp_bitcnt_t) 1 << i) > cap)
     157  	continue;		/* V^i would bring us past cap */
     158  
     159        qp[qn] = 0;
     160        mpn_bdiv_qr_wrap (qp2, tp, qp, qn + 1, pwpsp[i], pn);
     161        if (!mpn_zero_p (tp, pn))
     162  	{
     163  	  if (mpn_cmp (tp, pwpsp[i], pn) != 0)
     164  	    continue;		/* could not divide by V^i */
     165  	}
     166  
     167        MP_PTR_SWAP (qp, qp2);
     168        qn = qn - pn;
     169        mpn_neg (qp, qp, qn+1);
     170  
     171        qn += qp[qn] != 0;
     172  
     173        pwr += (mp_bitcnt_t) 1 << i;
     174      }
     175  
     176    MPN_COPY (wp, qp, qn);
     177    *wn = qn;
     178  
     179    TMP_FREE;
     180  
     181    return pwr;
     182  }