Home | History | Annotate | Line # | Download | only in mpz
      1      1.1  mrg /* mpz_remove -- divide out a factor and return its multiplicity.
      2      1.1  mrg 
      3  1.1.1.3  mrg Copyright 1998-2002, 2012 Free Software Foundation, Inc.
      4      1.1  mrg 
      5      1.1  mrg This file is part of the GNU MP Library.
      6      1.1  mrg 
      7      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
      8  1.1.1.3  mrg it under the terms of either:
      9  1.1.1.3  mrg 
     10  1.1.1.3  mrg   * the GNU Lesser General Public License as published by the Free
     11  1.1.1.3  mrg     Software Foundation; either version 3 of the License, or (at your
     12  1.1.1.3  mrg     option) any later version.
     13  1.1.1.3  mrg 
     14  1.1.1.3  mrg or
     15  1.1.1.3  mrg 
     16  1.1.1.3  mrg   * the GNU General Public License as published by the Free Software
     17  1.1.1.3  mrg     Foundation; either version 2 of the License, or (at your option) any
     18  1.1.1.3  mrg     later version.
     19  1.1.1.3  mrg 
     20  1.1.1.3  mrg or both in parallel, as here.
     21      1.1  mrg 
     22      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     23      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     24  1.1.1.3  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     25  1.1.1.3  mrg for more details.
     26      1.1  mrg 
     27  1.1.1.3  mrg You should have received copies of the GNU General Public License and the
     28  1.1.1.3  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     29  1.1.1.3  mrg see https://www.gnu.org/licenses/.  */
     30      1.1  mrg 
     31      1.1  mrg #include "gmp-impl.h"
     32      1.1  mrg 
     33      1.1  mrg mp_bitcnt_t
     34      1.1  mrg mpz_remove (mpz_ptr dest, mpz_srcptr src, mpz_srcptr f)
     35      1.1  mrg {
     36      1.1  mrg   mp_bitcnt_t pwr;
     37  1.1.1.2  mrg   mp_srcptr fp;
     38  1.1.1.2  mrg   mp_size_t sn, fn, afn;
     39  1.1.1.2  mrg   mp_limb_t fp0;
     40  1.1.1.2  mrg 
     41  1.1.1.2  mrg   sn = SIZ (src);
     42  1.1.1.2  mrg   fn = SIZ (f);
     43  1.1.1.2  mrg   fp = PTR (f);
     44  1.1.1.2  mrg   afn = ABS (fn);
     45  1.1.1.2  mrg   fp0 = fp[0];
     46      1.1  mrg 
     47  1.1.1.2  mrg   if (UNLIKELY ((afn <= (fp0 == 1)) /* mpz_cmpabs_ui (f, 1) <= 0 */
     48  1.1.1.2  mrg 		| (sn == 0)))
     49      1.1  mrg     {
     50  1.1.1.2  mrg       /*  f = 0 or f = +- 1 or src = 0 */
     51  1.1.1.2  mrg       if (afn == 0)
     52  1.1.1.2  mrg 	DIVIDE_BY_ZERO;
     53  1.1.1.2  mrg       mpz_set (dest, src);
     54      1.1  mrg       return 0;
     55      1.1  mrg     }
     56      1.1  mrg 
     57  1.1.1.2  mrg   if ((fp0 & 1) != 0)
     58  1.1.1.2  mrg     { /* f is odd */
     59  1.1.1.2  mrg       mp_ptr dp;
     60  1.1.1.2  mrg       mp_size_t dn;
     61      1.1  mrg 
     62  1.1.1.2  mrg       dn = ABS (sn);
     63  1.1.1.2  mrg       dp = MPZ_REALLOC (dest, dn);
     64      1.1  mrg 
     65  1.1.1.2  mrg       pwr = mpn_remove (dp, &dn, PTR(src), dn, PTR(f), afn, ~(mp_bitcnt_t) 0);
     66      1.1  mrg 
     67  1.1.1.2  mrg       SIZ (dest) = ((pwr & (fn < 0)) ^ (sn < 0)) ? -dn : dn;
     68  1.1.1.2  mrg     }
     69  1.1.1.2  mrg   else if (afn == (fp0 == 2))
     70  1.1.1.2  mrg     { /* mpz_cmpabs_ui (f, 2) == 0 */
     71  1.1.1.2  mrg       pwr = mpz_scan1 (src, 0);
     72  1.1.1.2  mrg       mpz_div_2exp (dest, src, pwr);
     73  1.1.1.2  mrg       if (pwr & (fn < 0)) /*((pwr % 2 == 1) && (SIZ (f) < 0))*/
     74  1.1.1.2  mrg 	mpz_neg (dest, dest);
     75  1.1.1.2  mrg     }
     76  1.1.1.2  mrg   else
     77  1.1.1.2  mrg     { /* f != +-2 */
     78  1.1.1.2  mrg       mpz_t x, rem;
     79  1.1.1.2  mrg 
     80  1.1.1.2  mrg       mpz_init (rem);
     81  1.1.1.2  mrg       mpz_init (x);
     82  1.1.1.2  mrg 
     83  1.1.1.2  mrg       pwr = 0;
     84  1.1.1.3  mrg       mpz_tdiv_qr (x, rem, src, f);
     85  1.1.1.3  mrg       if (SIZ (rem) == 0)
     86      1.1  mrg 	{
     87  1.1.1.3  mrg 	  mpz_t fpow[GMP_LIMB_BITS];		/* Really MP_SIZE_T_BITS */
     88  1.1.1.3  mrg 	  int p;
     89  1.1.1.2  mrg 
     90  1.1.1.3  mrg #if WANT_ORIGINAL_DEST
     91  1.1.1.3  mrg 	  mp_ptr dp;
     92  1.1.1.3  mrg 	  dp = PTR (dest);
     93  1.1.1.3  mrg #endif
     94  1.1.1.3  mrg       /* We could perhaps compute mpz_scan1(src,0)/mpz_scan1(f,0).  It is an
     95  1.1.1.3  mrg 	 upper bound of the result we're seeking.  We could also shift down the
     96  1.1.1.3  mrg 	 operands so that they become odd, to make intermediate values
     97  1.1.1.3  mrg 	 smaller.  */
     98  1.1.1.3  mrg 	  mpz_init_set (fpow[0], f);
     99  1.1.1.3  mrg 	  mpz_swap (dest, x);
    100  1.1.1.2  mrg 
    101  1.1.1.3  mrg 	  p = 1;
    102  1.1.1.3  mrg       /* Divide by f, f^2 ... f^(2^k) until we get a remainder for f^(2^k).  */
    103  1.1.1.3  mrg 	  while (ABSIZ (dest) >= 2 * ABSIZ (fpow[p - 1]) - 1)
    104  1.1.1.3  mrg 	    {
    105  1.1.1.3  mrg 	      mpz_init (fpow[p]);
    106  1.1.1.3  mrg 	      mpz_mul (fpow[p], fpow[p - 1], fpow[p - 1]);
    107  1.1.1.3  mrg 	      mpz_tdiv_qr (x, rem, dest, fpow[p]);
    108  1.1.1.3  mrg 	      if (SIZ (rem) != 0) {
    109  1.1.1.3  mrg 		mpz_clear (fpow[p]);
    110  1.1.1.3  mrg 		break;
    111  1.1.1.3  mrg 	      }
    112  1.1.1.3  mrg 	      mpz_swap (dest, x);
    113  1.1.1.3  mrg 	      p++;
    114  1.1.1.3  mrg 	    }
    115  1.1.1.3  mrg 
    116  1.1.1.3  mrg 	  pwr = ((mp_bitcnt_t)1 << p) - 1;
    117  1.1.1.2  mrg 
    118  1.1.1.2  mrg       /* Divide by f^(2^(k-1)), f^(2^(k-2)), ..., f for all divisors that give
    119  1.1.1.2  mrg 	 a zero remainder.  */
    120  1.1.1.3  mrg 	  while (--p >= 0)
    121  1.1.1.2  mrg 	    {
    122  1.1.1.3  mrg 	      mpz_tdiv_qr (x, rem, dest, fpow[p]);
    123  1.1.1.3  mrg 	      if (SIZ (rem) == 0)
    124  1.1.1.3  mrg 		{
    125  1.1.1.3  mrg 		  pwr += (mp_bitcnt_t)1 << p;
    126  1.1.1.3  mrg 		  mpz_swap (dest, x);
    127  1.1.1.3  mrg 		}
    128  1.1.1.3  mrg 	      mpz_clear (fpow[p]);
    129  1.1.1.2  mrg 	    }
    130  1.1.1.3  mrg 
    131  1.1.1.3  mrg #if WANT_ORIGINAL_DEST
    132  1.1.1.3  mrg 	  if (PTR (x) == dp) {
    133  1.1.1.3  mrg 	    mpz_swap (dest, x);
    134  1.1.1.3  mrg 	    mpz_set (dest, x);
    135  1.1.1.3  mrg 	  }
    136  1.1.1.3  mrg #endif
    137  1.1.1.2  mrg 	}
    138  1.1.1.3  mrg       else
    139  1.1.1.3  mrg 	mpz_set (dest, src);
    140  1.1.1.2  mrg 
    141  1.1.1.2  mrg       mpz_clear (x);
    142  1.1.1.2  mrg       mpz_clear (rem);
    143      1.1  mrg     }
    144      1.1  mrg 
    145      1.1  mrg   return pwr;
    146      1.1  mrg }
    147