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