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