github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpn/generic/perfpow.c (about) 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.h" 34 #include "gmp-impl.h" 35 #include "longlong.h" 36 37 #define SMALL 20 38 #define MEDIUM 100 39 40 /* Return non-zero if {np,nn} == {xp,xn} ^ k. 41 Algorithm: 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 44 {np,nn}. 45 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 50 base 2 logarithm. */ 51 static int 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, 55 mp_ptr tp) 56 { 57 mp_bitcnt_t y, z; 58 mp_size_t bn; 59 mp_limb_t h, l; 60 61 ASSERT (n > 1 || (n == 1 && np[0] > 1)); 62 ASSERT (np[n - 1] > 0); 63 ASSERT (xn > 0); 64 65 if (xn == 1 && xp[0] == 1) 66 return 0; 67 68 z = 1 + (n >> 1); 69 for (bn = 1; bn < z; bn <<= 1) 70 { 71 mpn_powlo (tp, xp, &k, 1, bn, tp + bn); 72 if (mpn_cmp (tp, np, bn) != 0) 73 return 0; 74 } 75 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 79 index of the MSB. */ 80 81 MPN_SIZEINBASE_2EXP(y, xp, xn, 1); 82 y -= 1; /* msb_index (xp, xn) */ 83 84 umul_ppmm (h, l, k, y); 85 h -= l == 0; --l; /* two-limb decrement */ 86 87 z = f - 1; /* msb_index (np, n) */ 88 if (h == 0 && l <= z) 89 { 90 mp_limb_t *tp2; 91 mp_size_t i; 92 int ans; 93 mp_limb_t size; 94 TMP_DECL; 95 96 size = l + k; 97 ASSERT_ALWAYS (size >= k); 98 99 TMP_MARK; 100 y = 2 + size / GMP_LIMB_BITS; 101 tp2 = TMP_ALLOC_LIMBS (y); 102 103 i = mpn_pow_1 (tp, xp, xn, k, tp2); 104 if (i == n && mpn_cmp (tp, np, n) == 0) 105 ans = 1; 106 else 107 ans = 0; 108 TMP_FREE; 109 return ans; 110 } 111 112 return 0; 113 } 114 115 116 /* Return non-zero if N = {np,n} is a kth power. 117 I = {ip,n} = N^(-1) mod B^n. */ 118 static int 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, 122 mp_ptr tp) 123 { 124 mp_bitcnt_t b; 125 mp_size_t rn, xn; 126 127 ASSERT (n > 0); 128 ASSERT ((k & 1) != 0 || k == 2); 129 ASSERT ((np[0] & 1) != 0); 130 131 if (k == 2) 132 { 133 b = (f + 1) >> 1; 134 rn = 1 + b / GMP_LIMB_BITS; 135 if (mpn_bsqrtinv (rp, ip, b, tp) != 0) 136 { 137 rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1; 138 xn = rn; 139 MPN_NORMALIZE (rp, xn); 140 if (pow_equals (np, n, rp, xn, k, f, tp) != 0) 141 return 1; 142 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) 148 return 1; 149 } 150 } 151 else 152 { 153 b = 1 + (f - 1) / k; 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) 160 return 1; 161 } 162 MPN_ZERO (rp, rn); /* Untrash rp */ 163 return 0; 164 } 165 166 static int 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) 170 { 171 mp_ptr ip, tp, rp; 172 mp_limb_t k; 173 int ans; 174 mp_bitcnt_t b; 175 gmp_primesieve_t ps; 176 TMP_DECL; 177 178 ASSERT (n > 0); 179 ASSERT ((np[0] & 1) != 0); 180 ASSERT (ub > 0); 181 182 TMP_MARK; 183 gmp_init_primesieve (&ps); 184 b = (f + 3) >> 1; 185 186 TMP_ALLOC_LIMBS_3 (ip, n, rp, n, tp, 5 * n); 187 188 MPN_ZERO (rp, n); 189 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; 199 200 if (neg) 201 gmp_nextprime (&ps); 202 203 ans = 0; 204 if (g > 0) 205 { 206 ub = MIN (ub, g + 1); 207 while ((k = gmp_nextprime (&ps)) < ub) 208 { 209 if ((g % k) == 0) 210 { 211 if (is_kth_power (rp, np, k, ip, n, f, tp) != 0) 212 { 213 ans = 1; 214 goto ret; 215 } 216 } 217 } 218 } 219 else 220 { 221 while ((k = gmp_nextprime (&ps)) < ub) 222 { 223 if (is_kth_power (rp, np, k, ip, n, f, tp) != 0) 224 { 225 ans = 1; 226 goto ret; 227 } 228 } 229 } 230 ret: 231 TMP_FREE; 232 return ans; 233 } 234 235 static const unsigned short nrtrial[] = { 100, 500, 1000 }; 236 237 /* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime 238 number. */ 239 static const double logs[] = 240 { 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 }; 241 242 int 243 mpn_perfect_power_p (mp_srcptr np, mp_size_t n) 244 { 245 mp_limb_t *nc, factor, g; 246 mp_limb_t exp, d; 247 mp_bitcnt_t twos, count; 248 int ans, where, neg, trial; 249 TMP_DECL; 250 251 neg = n < 0; 252 if (neg) 253 { 254 n = -n; 255 } 256 257 if (n == 0 || (n == 1 && np[0] == 1)) /* Valgrind doesn't like 258 (n <= (np[0] == 1)) */ 259 return 1; 260 261 TMP_MARK; 262 263 count = 0; 264 265 twos = mpn_scan1 (np, 0); 266 if (twos != 0) 267 { 268 mp_size_t s; 269 if (twos == 1) 270 { 271 return 0; 272 } 273 s = twos / GMP_LIMB_BITS; 274 if (s + 1 == n && POW2_P (np[s])) 275 { 276 return ! (neg && POW2_P (twos)); 277 } 278 count = twos % GMP_LIMB_BITS; 279 n -= s; 280 np += s; 281 if (count > 0) 282 { 283 nc = TMP_ALLOC_LIMBS (n); 284 mpn_rshift (nc, np, n, count); 285 n -= (nc[n - 1] == 0); 286 np = nc; 287 } 288 } 289 g = twos; 290 291 trial = (n > SMALL) + (n > MEDIUM); 292 293 where = 0; 294 factor = mpn_trialdiv (np, n, nrtrial[trial], &where); 295 296 if (factor != 0) 297 { 298 if (count == 0) /* We did not allocate nc yet. */ 299 { 300 nc = TMP_ALLOC_LIMBS (n); 301 } 302 303 /* Remove factors found by trialdiv. Optimization: If remove 304 define _itch, we can allocate its scratch just once */ 305 306 do 307 { 308 binvert_limb (d, factor); 309 310 /* After the first round we always have nc == np */ 311 exp = mpn_remove (nc, &n, np, n, &d, 1, ~(mp_bitcnt_t)0); 312 313 if (g == 0) 314 g = exp; 315 else 316 g = mpn_gcd_1 (&g, 1, exp); 317 318 if (g == 1) 319 { 320 ans = 0; 321 goto ret; 322 } 323 324 if ((n == 1) & (nc[0] == 1)) 325 { 326 ans = ! (neg && POW2_P (g)); 327 goto ret; 328 } 329 330 np = nc; 331 factor = mpn_trialdiv (np, n, nrtrial[trial], &where); 332 } 333 while (factor != 0); 334 } 335 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); 339 340 ret: 341 TMP_FREE; 342 return ans; 343 }