Coverage Report

Created: 2025-03-09 06:52

/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
515
#define SMALL 20
37
515
#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
7.15k
{
56
7.15k
  mp_bitcnt_t y, z;
57
7.15k
  mp_size_t bn;
58
7.15k
  mp_limb_t h, l;
59
60
7.15k
  ASSERT (n > 1 || (n == 1 && np[0] > 1));
61
7.15k
  ASSERT (np[n - 1] > 0);
62
7.15k
  ASSERT (xn > 0);
63
64
7.15k
  if (xn == 1 && xp[0] == 1)
65
4.48k
    return 0;
66
67
2.67k
  z = 1 + (n >> 1);
68
6.67k
  for (bn = 1; bn < z; bn <<= 1)
69
6.31k
    {
70
6.31k
      mpn_powlo (tp, xp, &k, 1, bn, tp + bn);
71
6.31k
      if (mpn_cmp (tp, np, bn) != 0)
72
2.31k
  return 0;
73
6.31k
    }
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
360
  MPN_SIZEINBASE_2EXP(y, xp, xn, 1);
81
360
  y -= 1;  /* msb_index (xp, xn) */
82
83
360
  umul_ppmm (h, l, k, y);
84
360
  h -= l == 0;  --l;  /* two-limb decrement */
85
86
360
  z = f - 1; /* msb_index (np, n) */
87
360
  if (h == 0 && l <= z)
88
360
    {
89
360
      mp_limb_t *tp2;
90
360
      mp_size_t i;
91
360
      int ans;
92
360
      mp_limb_t size;
93
360
      TMP_DECL;
94
95
360
      size = l + k;
96
360
      ASSERT_ALWAYS (size >= k);
97
98
360
      TMP_MARK;
99
360
      y = 2 + size / GMP_LIMB_BITS;
100
360
      tp2 = TMP_ALLOC_LIMBS (y);
101
102
360
      i = mpn_pow_1 (tp, xp, xn, k, tp2);
103
360
      if (i == n && mpn_cmp (tp, np, n) == 0)
104
0
  ans = 1;
105
360
      else
106
360
  ans = 0;
107
360
      TMP_FREE;
108
360
      return ans;
109
360
    }
110
111
0
  return 0;
112
360
}
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
7.05k
{
123
7.05k
  mp_bitcnt_t b;
124
7.05k
  mp_size_t rn, xn;
125
126
7.05k
  ASSERT (n > 0);
127
7.05k
  ASSERT ((k & 1) != 0 || k == 2);
128
7.05k
  ASSERT ((np[0] & 1) != 0);
129
130
7.05k
  if (k == 2)
131
207
    {
132
207
      b = (f + 1) >> 1;
133
207
      rn = 1 + b / GMP_LIMB_BITS;
134
207
      if (mpn_bsqrtinv (rp, ip, b, tp) != 0)
135
154
  {
136
154
    rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
137
154
    xn = rn;
138
154
    MPN_NORMALIZE (rp, xn);
139
154
    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
154
    mpn_neg (rp, rp, rn);
144
154
    rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
145
154
    MPN_NORMALIZE (rp, rn);
146
154
    if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
147
0
      return 1;
148
154
  }
149
207
    }
150
6.84k
  else
151
6.84k
    {
152
6.84k
      b = 1 + (f - 1) / k;
153
6.84k
      rn = 1 + (b - 1) / GMP_LIMB_BITS;
154
6.84k
      mpn_brootinv (rp, ip, rn, k, tp);
155
6.84k
      if ((b % GMP_LIMB_BITS) != 0)
156
6.79k
  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
157
6.84k
      MPN_NORMALIZE (rp, rn);
158
6.84k
      if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
159
0
  return 1;
160
6.84k
    }
161
7.05k
  MPN_ZERO (rp, rn); /* Untrash rp */
162
7.05k
  return 0;
163
7.05k
}
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
298
{
170
298
  mp_ptr ip, tp, rp;
171
298
  mp_limb_t k;
172
298
  int ans;
173
298
  mp_bitcnt_t b;
174
298
  gmp_primesieve_t ps;
175
298
  TMP_DECL;
176
177
298
  ASSERT (n > 0);
178
298
  ASSERT ((np[0] & 1) != 0);
179
298
  ASSERT (ub > 0);
180
181
298
  TMP_MARK;
182
298
  gmp_init_primesieve (&ps);
183
298
  b = (f + 3) >> 1;
184
185
298
  TMP_ALLOC_LIMBS_3 (ip, n, rp, n, tp, 5 * n);
186
187
298
  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
298
  mpn_binvert (ip, np, 1 + (b - 1) / GMP_LIMB_BITS, tp);
196
298
  if (b % GMP_LIMB_BITS)
197
285
    ip[(b - 1) / GMP_LIMB_BITS] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
198
199
298
  if (neg)
200
25
    gmp_nextprime (&ps);
201
202
298
  ans = 0;
203
298
  if (g > 0)
204
222
    {
205
222
      ub = MIN (ub, g + 1);
206
3.64k
      while ((k = gmp_nextprime (&ps)) < ub)
207
3.42k
  {
208
3.42k
    if ((g % k) == 0)
209
295
      {
210
295
        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
295
      }
216
3.42k
  }
217
222
    }
218
76
  else
219
76
    {
220
6.83k
      while ((k = gmp_nextprime (&ps)) < ub)
221
6.75k
  {
222
6.75k
    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
6.75k
  }
228
76
    }
229
298
 ret:
230
298
  TMP_FREE;
231
298
  return ans;
232
298
}
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
537
{
244
537
  mp_limb_t *nc, factor, g;
245
537
  mp_limb_t exp, d;
246
537
  mp_bitcnt_t twos, count;
247
537
  int ans, where, neg, trial;
248
537
  TMP_DECL;
249
250
537
  neg = n < 0;
251
537
  if (neg)
252
39
    {
253
39
      n = -n;
254
39
    }
255
256
537
  if (n == 0 || (n == 1 && np[0] == 1)) /* Valgrind doesn't like
257
             (n <= (np[0] == 1)) */
258
11
    return 1;
259
260
526
  TMP_MARK;
261
262
526
  count = 0;
263
264
526
  twos = mpn_scan1 (np, 0);
265
526
  if (twos != 0)
266
418
    {
267
418
      mp_size_t s;
268
418
      if (twos == 1)
269
11
  {
270
11
    return 0;
271
11
  }
272
407
      s = twos / GMP_LIMB_BITS;
273
407
      if (s + 1 == n && POW2_P (np[s]))
274
0
  {
275
0
    return ! (neg && POW2_P (twos));
276
0
  }
277
407
      count = twos % GMP_LIMB_BITS;
278
407
      n -= s;
279
407
      np += s;
280
407
      if (count > 0)
281
390
  {
282
390
    nc = TMP_ALLOC_LIMBS (n);
283
390
    mpn_rshift (nc, np, n, count);
284
390
    n -= (nc[n - 1] == 0);
285
390
    np = nc;
286
390
  }
287
407
    }
288
515
  g = twos;
289
290
515
  trial = (n > SMALL) + (n > MEDIUM);
291
292
515
  where = 0;
293
515
  factor = mpn_trialdiv (np, n, nrtrial[trial], &where);
294
295
515
  if (factor != 0)
296
438
    {
297
438
      if (count == 0) /* We did not allocate nc yet. */
298
49
  {
299
49
    nc = TMP_ALLOC_LIMBS (n);
300
49
  }
301
302
      /* Remove factors found by trialdiv.  Optimization: If remove
303
   define _itch, we can allocate its scratch just once */
304
305
438
      do
306
652
  {
307
652
    binvert_limb (d, factor);
308
309
    /* After the first round we always have nc == np */
310
652
    exp = mpn_remove (nc, &n, np, n, &d, 1, ~(mp_bitcnt_t)0);
311
312
652
    if (g == 0)
313
32
      g = exp;
314
620
    else
315
620
      g = mpn_gcd_1 (&g, 1, exp);
316
317
652
    if (g == 1)
318
200
      {
319
200
        ans = 0;
320
200
        goto ret;
321
200
      }
322
323
452
    if ((n == 1) & (nc[0] == 1))
324
17
      {
325
17
        ans = ! (neg && POW2_P (g));
326
17
        goto ret;
327
17
      }
328
329
435
    np = nc;
330
435
    factor = mpn_trialdiv (np, n, nrtrial[trial], &where);
331
435
  }
332
438
      while (factor != 0);
333
438
    }
334
335
298
  MPN_SIZEINBASE_2EXP(count, np, n, 1);   /* log (np) + 1 */
336
298
  d = (mp_limb_t) (count * logs[trial] + 1e-9) + 1;
337
298
  ans = perfpow (np, n, d, g, count, neg);
338
339
515
 ret:
340
515
  TMP_FREE;
341
515
  return ans;
342
298
}