perfpow.c revision 1.1.1.1.2.1 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.1.2.1 yamt 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.1.2.1 yamt /* Return non-zero if {np,nn} == {xp,xn} ^ k.
30 1.1 mrg Algorithm:
31 1.1.1.1.2.1 yamt For s = 1, 2, 4, ..., s_max, compute the s least significant limbs of
32 1.1.1.1.2.1 yamt {xp,xn}^k. Stop if they don't match the s least significant limbs of
33 1.1.1.1.2.1 yamt {np,nn}.
34 1.1.1.1.2.1 yamt
35 1.1.1.1.2.1 yamt FIXME: Low xn limbs can be expected to always match, if computed as a mod
36 1.1.1.1.2.1 yamt B^{xn} root. So instead of using mpn_powlo, compute an approximation of the
37 1.1.1.1.2.1 yamt most significant (normalized) limb of {xp,xn} ^ k (and an error bound), and
38 1.1.1.1.2.1 yamt compare to {np, nn}. Or use an even cruder approximation based on fix-point
39 1.1.1.1.2.1 yamt base 2 logarithm. */
40 1.1 mrg static int
41 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt ASSERT (n > 1 || (n == 1 && np[0] > 1));
54 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt /* Final check. Estimate the size of {xp,xn}^k before computing the power
71 1.1.1.1.2.1 yamt with full precision. Optimization: It might pay off to make a more
72 1.1.1.1.2.1 yamt accurate estimation of the logarithm of {xp,xn}, rather than using the
73 1.1.1.1.2.1 yamt index of the MSB. */
74 1.1 mrg
75 1.1.1.1.2.1 yamt MPN_SIZEINBASE_2EXP(y, xp, xn, 1);
76 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt /* Return non-zero if N = {np,n} is a kth power.
108 1.1.1.1.2.1 yamt 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.1.2.1 yamt mp_limb_t k, mp_srcptr ip,
112 1.1.1.1.2.1 yamt 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.1.2.1 yamt mp_size_t rn, xn;
117 1.1 mrg
118 1.1.1.1.2.1 yamt ASSERT (n > 0);
119 1.1.1.1.2.1 yamt 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.1.2.1 yamt if (mpn_bsqrtinv (rp, ip, b, tp) != 0)
127 1.1 mrg {
128 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt /* Check if (2^b - r)^2 == n */
135 1.1.1.1.2.1 yamt mpn_neg (rp, rp, rn);
136 1.1.1.1.2.1 yamt rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
137 1.1 mrg MPN_NORMALIZE (rp, rn);
138 1.1.1.1.2.1 yamt 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.1.2.1 yamt mpn_brootinv (rp, ip, rn, k, tp);
147 1.1.1.1.2.1 yamt if ((b % GMP_LIMB_BITS) != 0)
148 1.1.1.1.2.1 yamt rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
149 1.1 mrg MPN_NORMALIZE (rp, rn);
150 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt mp_ptr ip, tp, rp;
163 1.1.1.1.2.1 yamt mp_limb_t k;
164 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt ip = TMP_ALLOC_LIMBS (n);
178 1.1.1.1.2.1 yamt rp = TMP_ALLOC_LIMBS (n);
179 1.1.1.1.2.1 yamt tp = TMP_ALLOC_LIMBS (5 * n); /* FIXME */
180 1.1.1.1.2.1 yamt MPN_ZERO (rp, n);
181 1.1.1.1.2.1 yamt
182 1.1.1.1.2.1 yamt /* FIXME: It seems the inverse in ninv is needed only to get non-inverted
183 1.1.1.1.2.1 yamt roots. I.e., is_kth_power computes n^{1/2} as (n^{-1})^{-1/2} and
184 1.1.1.1.2.1 yamt similarly for nth roots. It should be more efficient to compute n^{1/2} as
185 1.1.1.1.2.1 yamt n * n^{-1/2}, with a mullo instead of a binvert. And we can do something
186 1.1.1.1.2.1 yamt similar for kth roots if we switch to an iteration converging to n^{1/k -
187 1.1.1.1.2.1 yamt 1}, and we can then eliminate this binvert call. */
188 1.1.1.1.2.1 yamt mpn_binvert (ip, np, 1 + (b - 1) / GMP_LIMB_BITS, tp);
189 1.1 mrg if (b % GMP_LIMB_BITS)
190 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt /* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime
230 1.1.1.1.2.1 yamt number. */
231 1.1.1.1.2.1 yamt static const double logs[] =
232 1.1.1.1.2.1 yamt { 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 };
233 1.1 mrg
234 1.1 mrg int
235 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt mp_bitcnt_t twos, count;
241 1.1.1.1.2.1 yamt 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.1.2.1 yamt neg = 0;
247 1.1.1.1.2.1 yamt if (n < 0)
248 1.1 mrg {
249 1.1 mrg neg = 1;
250 1.1.1.1.2.1 yamt n = -n;
251 1.1 mrg }
252 1.1 mrg
253 1.1.1.1.2.1 yamt 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.1.2.1 yamt g = 0;
259 1.1.1.1.2.1 yamt
260 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt 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.1.2.1 yamt /* Remove factors found by trialdiv. Optimization: Perhaps better to use
309 1.1.1.1.2.1 yamt 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.1.2.1 yamt 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