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