1
/* mpn_perfect_power_p -- mpn perfect power detection.
3
Contributed to the GNU project by Martin Boij.
5
Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
7
This file is part of the GNU MP Library.
9
The GNU MP Library is free software; you can redistribute it and/or modify
10
it under the terms of either:
12
* the GNU Lesser General Public License as published by the Free
13
Software Foundation; either version 3 of the License, or (at your
14
option) any later version.
18
* the GNU General Public License as published by the Free Software
19
Foundation; either version 2 of the License, or (at your option) any
22
or both in parallel, as here.
24
The GNU MP Library is distributed in the hope that it will be useful, but
25
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29
You should have received copies of the GNU General Public License and the
30
GNU Lesser General Public License along with the GNU MP Library. If not,
31
see https://www.gnu.org/licenses/. */
40
/* Return non-zero if {np,nn} == {xp,xn} ^ k.
42
For s = 1, 2, 4, ..., s_max, compute the s least significant limbs of
43
{xp,xn}^k. Stop if they don't match the s least significant limbs of
46
FIXME: Low xn limbs can be expected to always match, if computed as a mod
47
B^{xn} root. So instead of using mpn_powlo, compute an approximation of the
48
most significant (normalized) limb of {xp,xn} ^ k (and an error bound), and
49
compare to {np, nn}. Or use an even cruder approximation based on fix-point
52
pow_equals (mp_srcptr np, mp_size_t n,
53
mp_srcptr xp,mp_size_t xn,
54
mp_limb_t k, mp_bitcnt_t f,
64
ASSERT (n > 1 || (n == 1 && np[0] > 1));
65
ASSERT (np[n - 1] > 0);
68
if (xn == 1 && xp[0] == 1)
72
for (bn = 1; bn < z; bn <<= 1)
74
mpn_powlo (tp, xp, &k, 1, bn, tp + bn);
75
if (mpn_cmp (tp, np, bn) != 0)
81
/* Final check. Estimate the size of {xp,xn}^k before computing the power
82
with full precision. Optimization: It might pay off to make a more
83
accurate estimation of the logarithm of {xp,xn}, rather than using the
86
MPN_SIZEINBASE_2EXP(y, xp, xn, 1);
87
y -= 1; /* msb_index (xp, xn) */
89
umul_ppmm (h, l, k, y);
90
h -= l == 0; l--; /* two-limb decrement */
92
z = f - 1; /* msb_index (np, n) */
97
ASSERT_ALWAYS (size >= k);
99
y = 2 + size / GMP_LIMB_BITS;
100
tp2 = TMP_ALLOC_LIMBS (y);
102
i = mpn_pow_1 (tp, xp, xn, k, tp2);
103
if (i == n && mpn_cmp (tp, np, n) == 0)
118
/* Return non-zero if N = {np,n} is a kth power.
119
I = {ip,n} = N^(-1) mod B^n. */
121
is_kth_power (mp_ptr rp, mp_srcptr np,
122
mp_limb_t k, mp_srcptr ip,
123
mp_size_t n, mp_bitcnt_t f,
130
ASSERT ((k & 1) != 0 || k == 2);
131
ASSERT ((np[0] & 1) != 0);
136
rn = 1 + b / GMP_LIMB_BITS;
137
if (mpn_bsqrtinv (rp, ip, b, tp) != 0)
139
rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
141
MPN_NORMALIZE (rp, xn);
142
if (pow_equals (np, n, rp, xn, k, f, tp) != 0)
145
/* Check if (2^b - r)^2 == n */
146
mpn_neg (rp, rp, rn);
147
rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
148
MPN_NORMALIZE (rp, rn);
149
if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
156
rn = 1 + (b - 1) / GMP_LIMB_BITS;
157
mpn_brootinv (rp, ip, rn, k, tp);
158
if ((b % GMP_LIMB_BITS) != 0)
159
rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
160
MPN_NORMALIZE (rp, rn);
161
if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
164
MPN_ZERO (rp, rn); /* Untrash rp */
169
perfpow (mp_srcptr np, mp_size_t n,
170
mp_limb_t ub, mp_limb_t g,
171
mp_bitcnt_t f, int neg)
181
ASSERT ((np[0] & 1) != 0);
185
gmp_init_primesieve (&ps);
188
ip = TMP_ALLOC_LIMBS (n);
189
rp = TMP_ALLOC_LIMBS (n);
190
tp = TMP_ALLOC_LIMBS (5 * n); /* FIXME */
193
/* FIXME: It seems the inverse in ninv is needed only to get non-inverted
194
roots. I.e., is_kth_power computes n^{1/2} as (n^{-1})^{-1/2} and
195
similarly for nth roots. It should be more efficient to compute n^{1/2} as
196
n * n^{-1/2}, with a mullo instead of a binvert. And we can do something
197
similar for kth roots if we switch to an iteration converging to n^{1/k -
198
1}, and we can then eliminate this binvert call. */
199
mpn_binvert (ip, np, 1 + (b - 1) / GMP_LIMB_BITS, tp);
200
if (b % GMP_LIMB_BITS)
201
ip[(b - 1) / GMP_LIMB_BITS] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
209
ub = MIN (ub, g + 1);
210
while ((k = gmp_nextprime (&ps)) < ub)
214
if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
224
while ((k = gmp_nextprime (&ps)) < ub)
226
if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
238
static const unsigned short nrtrial[] = { 100, 500, 1000 };
240
/* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime
242
static const double logs[] =
243
{ 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 };
246
mpn_perfect_power_p (mp_srcptr np, mp_size_t n)
248
mp_size_t ncn, s, pn, xn;
249
mp_limb_t *nc, factor, g;
250
mp_limb_t exp, *prev, *next, d, l, r, c, *tp, cry;
251
mp_bitcnt_t twos, count;
252
int ans, where, neg, trial;
264
if (n == 0 || (n == 1 && np[0] == 1))
272
twos = mpn_scan1 (np, 0);
280
s = twos / GMP_LIMB_BITS;
281
if (s + 1 == n && POW2_P (np[s]))
283
ans = ! (neg && POW2_P (twos));
286
count = twos % GMP_LIMB_BITS;
288
nc = TMP_ALLOC_LIMBS (ncn);
291
mpn_rshift (nc, np + s, ncn, count);
292
ncn -= (nc[ncn - 1] == 0);
296
MPN_COPY (nc, np + s, ncn);
303
else if (ncn <= MEDIUM)
309
factor = mpn_trialdiv (nc, ncn, nrtrial[trial], &where);
315
nc = TMP_ALLOC_LIMBS (ncn);
316
MPN_COPY (nc, np, ncn);
319
/* Remove factors found by trialdiv. Optimization: Perhaps better to use
320
the strategy in mpz_remove (). */
321
prev = TMP_ALLOC_LIMBS (ncn + 2);
322
next = TMP_ALLOC_LIMBS (ncn + 2);
323
tp = TMP_ALLOC_LIMBS (4 * ncn);
327
binvert_limb (d, factor);
331
while (2 * pn - 1 <= ncn)
333
mpn_sqr (next, prev, pn);
335
xn -= (next[xn - 1] == 0);
337
if (mpn_divisible_p (nc, ncn, next, xn) == 0)
342
MP_PTR_SWAP (next, prev);
345
/* Binary search for the exponent */
353
xn = mpn_pow_1 (tp, &d, 1, c - exp, next);
354
if (pn + xn - 1 > ncn)
359
mpn_mul (next, prev, pn, tp, xn);
361
xn -= (next[xn - 1] == 0);
365
cry = mpn_mul_1 (next, prev, pn, d);
367
xn = pn + (cry != 0);
370
if (mpn_divisible_p (nc, ncn, next, xn) == 0)
378
MP_PTR_SWAP (next, prev);
386
g = mpn_gcd_1 (&g, 1, exp);
394
mpn_divexact (next, nc, ncn, prev, pn);
396
ncn += next[ncn] != 0;
397
MPN_COPY (nc, next, ncn);
399
if (ncn == 1 && nc[0] == 1)
401
ans = ! (neg && POW2_P (g));
405
factor = mpn_trialdiv (nc, ncn, nrtrial[trial], &where);
410
MPN_SIZEINBASE_2EXP(count, nc, ncn, 1); /* log (nc) + 1 */
411
d = (mp_limb_t) (count * logs[trial] + 1e-9) + 1;
412
ans = perfpow (nc, ncn, d, g, count, neg);