1 /* mpn_perfect_power_p -- mpn perfect power detection.
3 Contributed to the GNU project by Martin Boij.
5 Copyright 2009, 2010, 2012, 2014 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
,
61 ASSERT (n
> 1 || (n
== 1 && np
[0] > 1));
62 ASSERT (np
[n
- 1] > 0);
65 if (xn
== 1 && xp
[0] == 1)
69 for (bn
= 1; bn
< z
; bn
<<= 1)
71 mpn_powlo (tp
, xp
, &k
, 1, bn
, tp
+ bn
);
72 if (mpn_cmp (tp
, np
, bn
) != 0)
76 /* Final check. Estimate the size of {xp,xn}^k before computing the power
77 with full precision. Optimization: It might pay off to make a more
78 accurate estimation of the logarithm of {xp,xn}, rather than using the
81 MPN_SIZEINBASE_2EXP(y
, xp
, xn
, 1);
82 y
-= 1; /* msb_index (xp, xn) */
84 umul_ppmm (h
, l
, k
, y
);
85 h
-= l
== 0; --l
; /* two-limb decrement */
87 z
= f
- 1; /* msb_index (np, n) */
97 ASSERT_ALWAYS (size
>= k
);
100 y
= 2 + size
/ GMP_LIMB_BITS
;
101 tp2
= TMP_ALLOC_LIMBS (y
);
103 i
= mpn_pow_1 (tp
, xp
, xn
, k
, tp2
);
104 if (i
== n
&& mpn_cmp (tp
, np
, n
) == 0)
116 /* Return non-zero if N = {np,n} is a kth power.
117 I = {ip,n} = N^(-1) mod B^n. */
119 is_kth_power (mp_ptr rp
, mp_srcptr np
,
120 mp_limb_t k
, mp_srcptr ip
,
121 mp_size_t n
, mp_bitcnt_t f
,
128 ASSERT ((k
& 1) != 0 || k
== 2);
129 ASSERT ((np
[0] & 1) != 0);
134 rn
= 1 + b
/ GMP_LIMB_BITS
;
135 if (mpn_bsqrtinv (rp
, ip
, b
, tp
) != 0)
137 rp
[rn
- 1] &= (CNST_LIMB(1) << (b
% GMP_LIMB_BITS
)) - 1;
139 MPN_NORMALIZE (rp
, xn
);
140 if (pow_equals (np
, n
, rp
, xn
, k
, f
, tp
) != 0)
143 /* Check if (2^b - r)^2 == n */
144 mpn_neg (rp
, rp
, rn
);
145 rp
[rn
- 1] &= (CNST_LIMB(1) << (b
% GMP_LIMB_BITS
)) - 1;
146 MPN_NORMALIZE (rp
, rn
);
147 if (pow_equals (np
, n
, rp
, rn
, k
, f
, tp
) != 0)
154 rn
= 1 + (b
- 1) / GMP_LIMB_BITS
;
155 mpn_brootinv (rp
, ip
, rn
, k
, tp
);
156 if ((b
% GMP_LIMB_BITS
) != 0)
157 rp
[rn
- 1] &= (CNST_LIMB(1) << (b
% GMP_LIMB_BITS
)) - 1;
158 MPN_NORMALIZE (rp
, rn
);
159 if (pow_equals (np
, n
, rp
, rn
, k
, f
, tp
) != 0)
162 MPN_ZERO (rp
, rn
); /* Untrash rp */
167 perfpow (mp_srcptr np
, mp_size_t n
,
168 mp_limb_t ub
, mp_limb_t g
,
169 mp_bitcnt_t f
, int neg
)
179 ASSERT ((np
[0] & 1) != 0);
183 gmp_init_primesieve (&ps
);
186 TMP_ALLOC_LIMBS_3 (ip
, n
, rp
, n
, tp
, 5 * n
);
190 /* FIXME: It seems the inverse in ninv is needed only to get non-inverted
191 roots. I.e., is_kth_power computes n^{1/2} as (n^{-1})^{-1/2} and
192 similarly for nth roots. It should be more efficient to compute n^{1/2} as
193 n * n^{-1/2}, with a mullo instead of a binvert. And we can do something
194 similar for kth roots if we switch to an iteration converging to n^{1/k -
195 1}, and we can then eliminate this binvert call. */
196 mpn_binvert (ip
, np
, 1 + (b
- 1) / GMP_LIMB_BITS
, tp
);
197 if (b
% GMP_LIMB_BITS
)
198 ip
[(b
- 1) / GMP_LIMB_BITS
] &= (CNST_LIMB(1) << (b
% GMP_LIMB_BITS
)) - 1;
206 ub
= MIN (ub
, g
+ 1);
207 while ((k
= gmp_nextprime (&ps
)) < ub
)
211 if (is_kth_power (rp
, np
, k
, ip
, n
, f
, tp
) != 0)
221 while ((k
= gmp_nextprime (&ps
)) < ub
)
223 if (is_kth_power (rp
, np
, k
, ip
, n
, f
, tp
) != 0)
235 static const unsigned short nrtrial
[] = { 100, 500, 1000 };
237 /* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime
239 static const double logs
[] =
240 { 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 };
243 mpn_perfect_power_p (mp_srcptr np
, mp_size_t n
)
245 mp_limb_t
*nc
, factor
, g
;
247 mp_bitcnt_t twos
, count
;
248 int ans
, where
, neg
, trial
;
257 if (n
== 0 || (n
== 1 && np
[0] == 1)) /* Valgrind doesn't like
258 (n <= (np[0] == 1)) */
265 twos
= mpn_scan1 (np
, 0);
273 s
= twos
/ GMP_LIMB_BITS
;
274 if (s
+ 1 == n
&& POW2_P (np
[s
]))
276 return ! (neg
&& POW2_P (twos
));
278 count
= twos
% GMP_LIMB_BITS
;
283 nc
= TMP_ALLOC_LIMBS (n
);
284 mpn_rshift (nc
, np
, n
, count
);
285 n
-= (nc
[n
- 1] == 0);
291 trial
= (n
> SMALL
) + (n
> MEDIUM
);
294 factor
= mpn_trialdiv (np
, n
, nrtrial
[trial
], &where
);
298 if (count
== 0) /* We did not allocate nc yet. */
300 nc
= TMP_ALLOC_LIMBS (n
);
303 /* Remove factors found by trialdiv. Optimization: If remove
304 define _itch, we can allocate its scratch just once */
308 binvert_limb (d
, factor
);
310 /* After the first round we always have nc == np */
311 exp
= mpn_remove (nc
, &n
, np
, n
, &d
, 1, ~(mp_bitcnt_t
)0);
316 g
= mpn_gcd_1 (&g
, 1, exp
);
324 if ((n
== 1) & (nc
[0] == 1))
326 ans
= ! (neg
&& POW2_P (g
));
331 factor
= mpn_trialdiv (np
, n
, nrtrial
[trial
], &where
);
336 MPN_SIZEINBASE_2EXP(count
, np
, n
, 1); /* log (np) + 1 */
337 d
= (mp_limb_t
) (count
* logs
[trial
] + 1e-9) + 1;
338 ans
= perfpow (np
, n
, d
, g
, count
, neg
);