Home | History | Annotate | Line # | Download | only in generic
perfpow.c revision 1.1.1.2
      1      1.1  mrg /* mpn_perfect_power_p -- mpn perfect power detection.
      2      1.1  mrg 
      3      1.1  mrg    Contributed to the GNU project by Martin Boij.
      4      1.1  mrg 
      5  1.1.1.2  mrg Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
      6      1.1  mrg 
      7      1.1  mrg This file is part of the GNU MP Library.
      8      1.1  mrg 
      9      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
     10      1.1  mrg it under the terms of the GNU Lesser General Public License as published by
     11      1.1  mrg the Free Software Foundation; either version 3 of the License, or (at your
     12      1.1  mrg option) any later version.
     13      1.1  mrg 
     14      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     15      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     16      1.1  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     17      1.1  mrg License for more details.
     18      1.1  mrg 
     19      1.1  mrg You should have received a copy of the GNU Lesser General Public License
     20      1.1  mrg along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
     21      1.1  mrg 
     22      1.1  mrg #include "gmp.h"
     23      1.1  mrg #include "gmp-impl.h"
     24      1.1  mrg #include "longlong.h"
     25      1.1  mrg 
     26      1.1  mrg #define SMALL 20
     27      1.1  mrg #define MEDIUM 100
     28      1.1  mrg 
     29  1.1.1.2  mrg /* Return non-zero if {np,nn} == {xp,xn} ^ k.
     30      1.1  mrg    Algorithm:
     31  1.1.1.2  mrg        For s = 1, 2, 4, ..., s_max, compute the s least significant limbs of
     32  1.1.1.2  mrg        {xp,xn}^k. Stop if they don't match the s least significant limbs of
     33  1.1.1.2  mrg        {np,nn}.
     34  1.1.1.2  mrg 
     35  1.1.1.2  mrg    FIXME: Low xn limbs can be expected to always match, if computed as a mod
     36  1.1.1.2  mrg    B^{xn} root. So instead of using mpn_powlo, compute an approximation of the
     37  1.1.1.2  mrg    most significant (normalized) limb of {xp,xn} ^ k (and an error bound), and
     38  1.1.1.2  mrg    compare to {np, nn}. Or use an even cruder approximation based on fix-point
     39  1.1.1.2  mrg    base 2 logarithm.  */
     40      1.1  mrg static int
     41  1.1.1.2  mrg pow_equals (mp_srcptr np, mp_size_t n,
     42      1.1  mrg 	    mp_srcptr xp,mp_size_t xn,
     43      1.1  mrg 	    mp_limb_t k, mp_bitcnt_t f,
     44      1.1  mrg 	    mp_ptr tp)
     45      1.1  mrg {
     46      1.1  mrg   mp_limb_t *tp2;
     47  1.1.1.2  mrg   mp_bitcnt_t y, z;
     48      1.1  mrg   mp_size_t i, bn;
     49      1.1  mrg   int ans;
     50      1.1  mrg   mp_limb_t h, l;
     51      1.1  mrg   TMP_DECL;
     52      1.1  mrg 
     53  1.1.1.2  mrg   ASSERT (n > 1 || (n == 1 && np[0] > 1));
     54  1.1.1.2  mrg   ASSERT (np[n - 1] > 0);
     55      1.1  mrg   ASSERT (xn > 0);
     56      1.1  mrg 
     57      1.1  mrg   if (xn == 1 && xp[0] == 1)
     58      1.1  mrg     return 0;
     59      1.1  mrg 
     60  1.1.1.2  mrg   z = 1 + (n >> 1);
     61      1.1  mrg   for (bn = 1; bn < z; bn <<= 1)
     62      1.1  mrg     {
     63      1.1  mrg       mpn_powlo (tp, xp, &k, 1, bn, tp + bn);
     64      1.1  mrg       if (mpn_cmp (tp, np, bn) != 0)
     65      1.1  mrg 	return 0;
     66      1.1  mrg     }
     67      1.1  mrg 
     68      1.1  mrg   TMP_MARK;
     69      1.1  mrg 
     70  1.1.1.2  mrg   /* Final check. Estimate the size of {xp,xn}^k before computing the power
     71  1.1.1.2  mrg      with full precision.  Optimization: It might pay off to make a more
     72  1.1.1.2  mrg      accurate estimation of the logarithm of {xp,xn}, rather than using the
     73  1.1.1.2  mrg      index of the MSB.  */
     74      1.1  mrg 
     75  1.1.1.2  mrg   MPN_SIZEINBASE_2EXP(y, xp, xn, 1);
     76  1.1.1.2  mrg   y -= 1;  /* msb_index (xp, xn) */
     77      1.1  mrg 
     78      1.1  mrg   umul_ppmm (h, l, k, y);
     79      1.1  mrg   h -= l == 0;  l--;	/* two-limb decrement */
     80      1.1  mrg 
     81  1.1.1.2  mrg   z = f - 1; /* msb_index (np, n) */
     82      1.1  mrg   if (h == 0 && l <= z)
     83      1.1  mrg     {
     84      1.1  mrg       mp_limb_t size;
     85      1.1  mrg       size = l + k;
     86      1.1  mrg       ASSERT_ALWAYS (size >= k);
     87      1.1  mrg 
     88      1.1  mrg       y = 2 + size / GMP_LIMB_BITS;
     89      1.1  mrg       tp2 = TMP_ALLOC_LIMBS (y);
     90      1.1  mrg 
     91      1.1  mrg       i = mpn_pow_1 (tp, xp, xn, k, tp2);
     92  1.1.1.2  mrg       if (i == n && mpn_cmp (tp, np, n) == 0)
     93      1.1  mrg 	ans = 1;
     94      1.1  mrg       else
     95      1.1  mrg 	ans = 0;
     96      1.1  mrg     }
     97      1.1  mrg   else
     98      1.1  mrg     {
     99      1.1  mrg       ans = 0;
    100      1.1  mrg     }
    101      1.1  mrg 
    102      1.1  mrg   TMP_FREE;
    103      1.1  mrg   return ans;
    104      1.1  mrg }
    105      1.1  mrg 
    106      1.1  mrg 
    107  1.1.1.2  mrg /* Return non-zero if N = {np,n} is a kth power.
    108  1.1.1.2  mrg    I = {ip,n} = N^(-1) mod B^n.  */
    109      1.1  mrg static int
    110      1.1  mrg is_kth_power (mp_ptr rp, mp_srcptr np,
    111  1.1.1.2  mrg 	      mp_limb_t k, mp_srcptr ip,
    112  1.1.1.2  mrg 	      mp_size_t n, mp_bitcnt_t f,
    113      1.1  mrg 	      mp_ptr tp)
    114      1.1  mrg {
    115      1.1  mrg   mp_bitcnt_t b;
    116  1.1.1.2  mrg   mp_size_t rn, xn;
    117      1.1  mrg 
    118  1.1.1.2  mrg   ASSERT (n > 0);
    119  1.1.1.2  mrg   ASSERT ((k & 1) != 0 || k == 2);
    120      1.1  mrg   ASSERT ((np[0] & 1) != 0);
    121      1.1  mrg 
    122      1.1  mrg   if (k == 2)
    123      1.1  mrg     {
    124      1.1  mrg       b = (f + 1) >> 1;
    125      1.1  mrg       rn = 1 + b / GMP_LIMB_BITS;
    126  1.1.1.2  mrg       if (mpn_bsqrtinv (rp, ip, b, tp) != 0)
    127      1.1  mrg 	{
    128  1.1.1.2  mrg 	  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
    129      1.1  mrg 	  xn = rn;
    130      1.1  mrg 	  MPN_NORMALIZE (rp, xn);
    131  1.1.1.2  mrg 	  if (pow_equals (np, n, rp, xn, k, f, tp) != 0)
    132      1.1  mrg 	    return 1;
    133      1.1  mrg 
    134  1.1.1.2  mrg 	  /* Check if (2^b - r)^2 == n */
    135  1.1.1.2  mrg 	  mpn_neg (rp, rp, rn);
    136  1.1.1.2  mrg 	  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
    137      1.1  mrg 	  MPN_NORMALIZE (rp, rn);
    138  1.1.1.2  mrg 	  if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
    139      1.1  mrg 	    return 1;
    140      1.1  mrg 	}
    141      1.1  mrg     }
    142      1.1  mrg   else
    143      1.1  mrg     {
    144      1.1  mrg       b = 1 + (f - 1) / k;
    145      1.1  mrg       rn = 1 + (b - 1) / GMP_LIMB_BITS;
    146  1.1.1.2  mrg       mpn_brootinv (rp, ip, rn, k, tp);
    147  1.1.1.2  mrg       if ((b % GMP_LIMB_BITS) != 0)
    148  1.1.1.2  mrg 	rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
    149      1.1  mrg       MPN_NORMALIZE (rp, rn);
    150  1.1.1.2  mrg       if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
    151      1.1  mrg 	return 1;
    152      1.1  mrg     }
    153      1.1  mrg   MPN_ZERO (rp, rn); /* Untrash rp */
    154      1.1  mrg   return 0;
    155      1.1  mrg }
    156      1.1  mrg 
    157      1.1  mrg static int
    158  1.1.1.2  mrg perfpow (mp_srcptr np, mp_size_t n,
    159      1.1  mrg 	 mp_limb_t ub, mp_limb_t g,
    160      1.1  mrg 	 mp_bitcnt_t f, int neg)
    161      1.1  mrg {
    162  1.1.1.2  mrg   mp_ptr ip, tp, rp;
    163  1.1.1.2  mrg   mp_limb_t k;
    164  1.1.1.2  mrg   int ans;
    165      1.1  mrg   mp_bitcnt_t b;
    166      1.1  mrg   gmp_primesieve_t ps;
    167      1.1  mrg   TMP_DECL;
    168      1.1  mrg 
    169  1.1.1.2  mrg   ASSERT (n > 0);
    170      1.1  mrg   ASSERT ((np[0] & 1) != 0);
    171      1.1  mrg   ASSERT (ub > 0);
    172      1.1  mrg 
    173      1.1  mrg   TMP_MARK;
    174      1.1  mrg   gmp_init_primesieve (&ps);
    175      1.1  mrg   b = (f + 3) >> 1;
    176      1.1  mrg 
    177  1.1.1.2  mrg   ip = TMP_ALLOC_LIMBS (n);
    178  1.1.1.2  mrg   rp = TMP_ALLOC_LIMBS (n);
    179  1.1.1.2  mrg   tp = TMP_ALLOC_LIMBS (5 * n);		/* FIXME */
    180  1.1.1.2  mrg   MPN_ZERO (rp, n);
    181  1.1.1.2  mrg 
    182  1.1.1.2  mrg   /* FIXME: It seems the inverse in ninv is needed only to get non-inverted
    183  1.1.1.2  mrg      roots. I.e., is_kth_power computes n^{1/2} as (n^{-1})^{-1/2} and
    184  1.1.1.2  mrg      similarly for nth roots. It should be more efficient to compute n^{1/2} as
    185  1.1.1.2  mrg      n * n^{-1/2}, with a mullo instead of a binvert. And we can do something
    186  1.1.1.2  mrg      similar for kth roots if we switch to an iteration converging to n^{1/k -
    187  1.1.1.2  mrg      1}, and we can then eliminate this binvert call. */
    188  1.1.1.2  mrg   mpn_binvert (ip, np, 1 + (b - 1) / GMP_LIMB_BITS, tp);
    189      1.1  mrg   if (b % GMP_LIMB_BITS)
    190  1.1.1.2  mrg     ip[(b - 1) / GMP_LIMB_BITS] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
    191      1.1  mrg 
    192      1.1  mrg   if (neg)
    193      1.1  mrg     gmp_nextprime (&ps);
    194      1.1  mrg 
    195  1.1.1.2  mrg   ans = 0;
    196      1.1  mrg   if (g > 0)
    197      1.1  mrg     {
    198      1.1  mrg       ub = MIN (ub, g + 1);
    199      1.1  mrg       while ((k = gmp_nextprime (&ps)) < ub)
    200      1.1  mrg 	{
    201      1.1  mrg 	  if ((g % k) == 0)
    202      1.1  mrg 	    {
    203  1.1.1.2  mrg 	      if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
    204      1.1  mrg 		{
    205      1.1  mrg 		  ans = 1;
    206      1.1  mrg 		  goto ret;
    207      1.1  mrg 		}
    208      1.1  mrg 	    }
    209      1.1  mrg 	}
    210      1.1  mrg     }
    211      1.1  mrg   else
    212      1.1  mrg     {
    213      1.1  mrg       while ((k = gmp_nextprime (&ps)) < ub)
    214      1.1  mrg 	{
    215  1.1.1.2  mrg 	  if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
    216      1.1  mrg 	    {
    217      1.1  mrg 	      ans = 1;
    218      1.1  mrg 	      goto ret;
    219      1.1  mrg 	    }
    220      1.1  mrg 	}
    221      1.1  mrg     }
    222      1.1  mrg  ret:
    223      1.1  mrg   TMP_FREE;
    224      1.1  mrg   return ans;
    225      1.1  mrg }
    226      1.1  mrg 
    227      1.1  mrg static const unsigned short nrtrial[] = { 100, 500, 1000 };
    228      1.1  mrg 
    229  1.1.1.2  mrg /* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime
    230  1.1.1.2  mrg    number.  */
    231  1.1.1.2  mrg static const double logs[] =
    232  1.1.1.2  mrg   { 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 };
    233      1.1  mrg 
    234      1.1  mrg int
    235  1.1.1.2  mrg mpn_perfect_power_p (mp_srcptr np, mp_size_t n)
    236      1.1  mrg {
    237      1.1  mrg   mp_size_t ncn, s, pn, xn;
    238  1.1.1.2  mrg   mp_limb_t *nc, factor, g;
    239      1.1  mrg   mp_limb_t exp, *prev, *next, d, l, r, c, *tp, cry;
    240  1.1.1.2  mrg   mp_bitcnt_t twos, count;
    241  1.1.1.2  mrg   int ans, where, neg, trial;
    242      1.1  mrg   TMP_DECL;
    243      1.1  mrg 
    244      1.1  mrg   nc = (mp_ptr) np;
    245      1.1  mrg 
    246  1.1.1.2  mrg   neg = 0;
    247  1.1.1.2  mrg   if (n < 0)
    248      1.1  mrg     {
    249      1.1  mrg       neg = 1;
    250  1.1.1.2  mrg       n = -n;
    251      1.1  mrg     }
    252      1.1  mrg 
    253  1.1.1.2  mrg   if (n == 0 || (n == 1 && np[0] == 1))
    254      1.1  mrg     return 1;
    255      1.1  mrg 
    256      1.1  mrg   TMP_MARK;
    257      1.1  mrg 
    258  1.1.1.2  mrg   g = 0;
    259  1.1.1.2  mrg 
    260  1.1.1.2  mrg   ncn = n;
    261      1.1  mrg   twos = mpn_scan1 (np, 0);
    262      1.1  mrg   if (twos > 0)
    263      1.1  mrg     {
    264      1.1  mrg       if (twos == 1)
    265      1.1  mrg 	{
    266      1.1  mrg 	  ans = 0;
    267      1.1  mrg 	  goto ret;
    268      1.1  mrg 	}
    269      1.1  mrg       s = twos / GMP_LIMB_BITS;
    270  1.1.1.2  mrg       if (s + 1 == n && POW2_P (np[s]))
    271      1.1  mrg 	{
    272      1.1  mrg 	  ans = ! (neg && POW2_P (twos));
    273      1.1  mrg 	  goto ret;
    274      1.1  mrg 	}
    275      1.1  mrg       count = twos % GMP_LIMB_BITS;
    276  1.1.1.2  mrg       ncn = n - s;
    277      1.1  mrg       nc = TMP_ALLOC_LIMBS (ncn);
    278      1.1  mrg       if (count > 0)
    279      1.1  mrg 	{
    280      1.1  mrg 	  mpn_rshift (nc, np + s, ncn, count);
    281      1.1  mrg 	  ncn -= (nc[ncn - 1] == 0);
    282      1.1  mrg 	}
    283      1.1  mrg       else
    284      1.1  mrg 	{
    285      1.1  mrg 	  MPN_COPY (nc, np + s, ncn);
    286      1.1  mrg 	}
    287      1.1  mrg       g = twos;
    288      1.1  mrg     }
    289      1.1  mrg 
    290      1.1  mrg   if (ncn <= SMALL)
    291      1.1  mrg     trial = 0;
    292      1.1  mrg   else if (ncn <= MEDIUM)
    293      1.1  mrg     trial = 1;
    294      1.1  mrg   else
    295      1.1  mrg     trial = 2;
    296      1.1  mrg 
    297  1.1.1.2  mrg   where = 0;
    298      1.1  mrg   factor = mpn_trialdiv (nc, ncn, nrtrial[trial], &where);
    299      1.1  mrg 
    300      1.1  mrg   if (factor != 0)
    301      1.1  mrg     {
    302      1.1  mrg       if (twos == 0)
    303      1.1  mrg 	{
    304      1.1  mrg 	  nc = TMP_ALLOC_LIMBS (ncn);
    305      1.1  mrg 	  MPN_COPY (nc, np, ncn);
    306      1.1  mrg 	}
    307      1.1  mrg 
    308  1.1.1.2  mrg       /* Remove factors found by trialdiv.  Optimization: Perhaps better to use
    309  1.1.1.2  mrg 	 the strategy in mpz_remove ().  */
    310      1.1  mrg       prev = TMP_ALLOC_LIMBS (ncn + 2);
    311      1.1  mrg       next = TMP_ALLOC_LIMBS (ncn + 2);
    312      1.1  mrg       tp = TMP_ALLOC_LIMBS (4 * ncn);
    313      1.1  mrg 
    314      1.1  mrg       do
    315      1.1  mrg 	{
    316      1.1  mrg 	  binvert_limb (d, factor);
    317      1.1  mrg 	  prev[0] = d;
    318      1.1  mrg 	  pn = 1;
    319      1.1  mrg 	  exp = 1;
    320      1.1  mrg 	  while (2 * pn - 1 <= ncn)
    321      1.1  mrg 	    {
    322      1.1  mrg 	      mpn_sqr (next, prev, pn);
    323      1.1  mrg 	      xn = 2 * pn;
    324      1.1  mrg 	      xn -= (next[xn - 1] == 0);
    325      1.1  mrg 
    326      1.1  mrg 	      if (mpn_divisible_p (nc, ncn, next, xn) == 0)
    327      1.1  mrg 		break;
    328      1.1  mrg 
    329      1.1  mrg 	      exp <<= 1;
    330      1.1  mrg 	      pn = xn;
    331      1.1  mrg 	      MP_PTR_SWAP (next, prev);
    332      1.1  mrg 	    }
    333      1.1  mrg 
    334      1.1  mrg 	  /* Binary search for the exponent */
    335      1.1  mrg 	  l = exp + 1;
    336      1.1  mrg 	  r = 2 * exp - 1;
    337      1.1  mrg 	  while (l <= r)
    338      1.1  mrg 	    {
    339      1.1  mrg 	      c = (l + r) >> 1;
    340      1.1  mrg 	      if (c - exp > 1)
    341      1.1  mrg 		{
    342      1.1  mrg 		  xn = mpn_pow_1 (tp, &d, 1, c - exp, next);
    343      1.1  mrg 		  if (pn + xn - 1 > ncn)
    344      1.1  mrg 		    {
    345      1.1  mrg 		      r = c - 1;
    346      1.1  mrg 		      continue;
    347      1.1  mrg 		    }
    348      1.1  mrg 		  mpn_mul (next, prev, pn, tp, xn);
    349      1.1  mrg 		  xn += pn;
    350      1.1  mrg 		  xn -= (next[xn - 1] == 0);
    351      1.1  mrg 		}
    352      1.1  mrg 	      else
    353      1.1  mrg 		{
    354      1.1  mrg 		  cry = mpn_mul_1 (next, prev, pn, d);
    355      1.1  mrg 		  next[pn] = cry;
    356      1.1  mrg 		  xn = pn + (cry != 0);
    357      1.1  mrg 		}
    358      1.1  mrg 
    359      1.1  mrg 	      if (mpn_divisible_p (nc, ncn, next, xn) == 0)
    360      1.1  mrg 		{
    361      1.1  mrg 		  r = c - 1;
    362      1.1  mrg 		}
    363      1.1  mrg 	      else
    364      1.1  mrg 		{
    365      1.1  mrg 		  exp = c;
    366      1.1  mrg 		  l = c + 1;
    367      1.1  mrg 		  MP_PTR_SWAP (next, prev);
    368      1.1  mrg 		  pn = xn;
    369      1.1  mrg 		}
    370      1.1  mrg 	    }
    371      1.1  mrg 
    372      1.1  mrg 	  if (g == 0)
    373      1.1  mrg 	    g = exp;
    374      1.1  mrg 	  else
    375      1.1  mrg 	    g = mpn_gcd_1 (&g, 1, exp);
    376      1.1  mrg 
    377      1.1  mrg 	  if (g == 1)
    378      1.1  mrg 	    {
    379      1.1  mrg 	      ans = 0;
    380      1.1  mrg 	      goto ret;
    381      1.1  mrg 	    }
    382      1.1  mrg 
    383      1.1  mrg 	  mpn_divexact (next, nc, ncn, prev, pn);
    384      1.1  mrg 	  ncn = ncn - pn;
    385      1.1  mrg 	  ncn += next[ncn] != 0;
    386      1.1  mrg 	  MPN_COPY (nc, next, ncn);
    387      1.1  mrg 
    388      1.1  mrg 	  if (ncn == 1 && nc[0] == 1)
    389      1.1  mrg 	    {
    390      1.1  mrg 	      ans = ! (neg && POW2_P (g));
    391      1.1  mrg 	      goto ret;
    392      1.1  mrg 	    }
    393      1.1  mrg 
    394      1.1  mrg 	  factor = mpn_trialdiv (nc, ncn, nrtrial[trial], &where);
    395      1.1  mrg 	}
    396      1.1  mrg       while (factor != 0);
    397      1.1  mrg     }
    398      1.1  mrg 
    399  1.1.1.2  mrg   MPN_SIZEINBASE_2EXP(count, nc, ncn, 1);   /* log (nc) + 1 */
    400      1.1  mrg   d = (mp_limb_t) (count * logs[trial] + 1e-9) + 1;
    401      1.1  mrg   ans = perfpow (nc, ncn, d, g, count, neg);
    402      1.1  mrg 
    403      1.1  mrg  ret:
    404      1.1  mrg   TMP_FREE;
    405      1.1  mrg   return ans;
    406      1.1  mrg }
    407