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