Coverage Report

Created: 2024-11-21 07:03

/src/libgmp/mpz/nextprime.c
Line
Count
Source (jump to first uncovered line)
1
/* mpz_nextprime(p,t) - compute the next prime > t and store that in p.
2
3
Copyright 1999-2001, 2008, 2009, 2012, 2020-2022 Free Software
4
Foundation, Inc.
5
6
Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
7
Improved by Seth Troisi.
8
9
This file is part of the GNU MP Library.
10
11
The GNU MP Library is free software; you can redistribute it and/or modify
12
it under the terms of either:
13
14
  * the GNU Lesser General Public License as published by the Free
15
    Software Foundation; either version 3 of the License, or (at your
16
    option) any later version.
17
18
or
19
20
  * the GNU General Public License as published by the Free Software
21
    Foundation; either version 2 of the License, or (at your option) any
22
    later version.
23
24
or both in parallel, as here.
25
26
The GNU MP Library is distributed in the hope that it will be useful, but
27
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
28
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
29
for more details.
30
31
You should have received copies of the GNU General Public License and the
32
GNU Lesser General Public License along with the GNU MP Library.  If not,
33
see https://www.gnu.org/licenses/.  */
34
35
#include <string.h>
36
37
#include "gmp-impl.h"
38
#include "longlong.h"
39
40
/*********************************************************/
41
/* Section sieve: sieving functions and tools for primes */
42
/*********************************************************/
43
44
static mp_limb_t
45
2.49k
n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
46
47
static mp_size_t
48
2.49k
primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
49
50
51
static const unsigned char primegap_small[] =
52
{
53
  2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,
54
  2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2,
55
  4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,2,10,2,6,4,6,8,4,2,4,12,8,4,8,4,6,
56
  12,2,18,6,10
57
};
58
59
2.02k
#define NUMBER_OF_PRIMES 100
60
#define LAST_PRIME 557
61
/* NP_SMALL_LIMIT = prevprime (LAST_PRIME ^ 2) */
62
#define NP_SMALL_LIMIT 310243
63
64
static unsigned long
65
1.24k
calculate_sievelimit(mp_bitcnt_t nbits) {
66
1.24k
  unsigned long sieve_limit;
67
68
  /* Estimate a good sieve bound. Based on derivative of
69
   *   Merten's 3rd theorem * avg gap * cost of mod
70
   *      vs
71
   *   Cost of PRP test O(N^2.55)
72
   */
73
1.24k
  if (nbits < 12818)
74
1.24k
    {
75
1.24k
      mpz_t tmp;
76
      /* sieve_limit ~= nbits ^ (5/2) / 124 */
77
1.24k
      mpz_init (tmp);
78
1.24k
      mpz_ui_pow_ui (tmp, nbits, 5);
79
1.24k
      mpz_tdiv_q_ui(tmp, tmp, 124*124);
80
      /* tmp < 12818^5/(124*124) < 2^55 < 2^64 */
81
1.24k
      mpz_sqrt (tmp, tmp);
82
83
1.24k
      sieve_limit = mpz_get_ui(tmp);
84
1.24k
      mpz_clear (tmp);
85
1.24k
    }
86
0
  else
87
0
    {
88
      /* Larger threshold is faster but takes (n/ln(n) + n/24) memory.
89
       * For 33,000 bits limitting to 150M is ~12% slower than using the
90
       * optimal 1.5G sieve_limit.
91
       */
92
0
      sieve_limit = 150000001;
93
0
    }
94
95
1.24k
  ASSERT (1000 < sieve_limit && sieve_limit <= 150000001);
96
1.24k
  return sieve_limit;
97
1.24k
}
98
99
static unsigned
100
findnext_small (unsigned t, short diff)
101
128
{
102
  /* For diff= 2, expect t = 1 if operand was negative.
103
   * For diff=-2, expect t >= 3
104
   */
105
128
  ASSERT (t >= 3 || (diff > 0 && t >= 1));
106
128
  ASSERT (t < NP_SMALL_LIMIT);
107
108
  /* Start from next candidate (2 or odd) */
109
128
  t = diff > 0 ?
110
128
    (t + 1) | (t != 1) :
111
128
    ((t - 2) | 1) + (t == 3);
112
113
128
  for (; ; t += diff)
114
193
    {
115
193
      unsigned prime = 3;
116
1.17k
      for (int i = 0; ; prime += primegap_small[i++])
117
1.37k
  {
118
1.37k
    unsigned q, r;
119
1.37k
    q = t / prime;
120
1.37k
    r = t - q * prime; /* r = t % prime; */
121
1.37k
    if (q < prime)
122
128
      return t;
123
1.24k
    if (r == 0)
124
65
      break;
125
1.17k
    ASSERT (i < NUMBER_OF_PRIMES);
126
1.17k
  }
127
193
    }
128
128
}
129
130
static int
131
findnext (mpz_ptr p,
132
          unsigned long(*negative_mod_ui)(const mpz_t, unsigned long),
133
          void(*increment_ui)(mpz_t, const mpz_t, unsigned long))
134
2.02k
{
135
2.02k
  char *composite;
136
2.02k
  const unsigned char *primegap;
137
2.02k
  unsigned long prime_limit;
138
2.02k
  mp_size_t pn;
139
2.02k
  mp_bitcnt_t nbits;
140
2.02k
  int i, m;
141
2.02k
  unsigned odds_in_composite_sieve;
142
2.02k
  TMP_DECL;
143
144
2.02k
  TMP_MARK;
145
2.02k
  pn = SIZ(p);
146
2.02k
  MPN_SIZEINBASE_2EXP(nbits, PTR(p), pn, 1);
147
  /* Smaller numbers handled earlier */
148
2.02k
  ASSERT (nbits >= 3);
149
  /* Make p odd */
150
2.02k
  PTR(p)[0] |= 1;
151
152
2.02k
  if (nbits / 2 <= NUMBER_OF_PRIMES)
153
778
    {
154
778
      primegap = primegap_small;
155
778
      prime_limit = nbits / 2;
156
778
    }
157
1.24k
  else
158
1.24k
    {
159
1.24k
      unsigned long sieve_limit;
160
1.24k
      mp_limb_t *sieve;
161
1.24k
      unsigned char *primegap_tmp;
162
1.24k
      unsigned long last_prime;
163
164
      /* sieve numbers up to sieve_limit and save prime count */
165
1.24k
      sieve_limit = calculate_sievelimit(nbits);
166
1.24k
      sieve = TMP_ALLOC_LIMBS (primesieve_size (sieve_limit));
167
1.24k
      prime_limit = gmp_primesieve(sieve, sieve_limit);
168
169
      /* TODO: Storing (prime - last_prime)/2 would allow this to go
170
   up to the gap 304599508537+514=304599509051 .
171
   With the current code our limit is 436273009+282=436273291 */
172
1.24k
      ASSERT (sieve_limit < 436273291);
173
      /* THINK: Memory used by both sieve and primegap_tmp is kept
174
   allocated, but they may overlap if primegap is filled from
175
   larger down to smaller primes...
176
       */
177
178
      /* Needed to avoid assignment of read-only location */
179
1.24k
      primegap_tmp = TMP_ALLOC_TYPE (prime_limit, unsigned char);
180
1.24k
      primegap = primegap_tmp;
181
182
1.24k
      i = 0;
183
1.24k
      last_prime = 3;
184
      /* THINK: should we get rid of sieve_limit and use (i < prime_limit)? */
185
166k
      for (mp_limb_t j = 4, *sp = sieve; j < sieve_limit; j += GMP_LIMB_BITS * 3)
186
10.4M
  for (mp_limb_t b = j, x = ~ *(sp++); x != 0; b += 3, x >>= 1)
187
10.2M
    if (x & 1)
188
3.44M
      {
189
3.44M
        mp_limb_t prime = b | 1;
190
3.44M
        primegap_tmp[i++] = prime - last_prime;
191
3.44M
        last_prime = prime;
192
3.44M
      }
193
194
      /* Both primesieve and prime_limit ignore the first two primes. */
195
1.24k
      ASSERT(i == prime_limit);
196
1.24k
    }
197
198
2.02k
  if (nbits <= 32)
199
166
    odds_in_composite_sieve = 336 / 2;
200
1.86k
  else if (nbits <= 64)
201
240
    odds_in_composite_sieve = 1550 / 2;
202
1.62k
  else
203
    /* Corresponds to a merit 14 prime_gap, which is rare. */
204
1.62k
    odds_in_composite_sieve = 5 * nbits;
205
206
  /* composite[2*i] stores if p+2*i is a known composite */
207
2.02k
  composite = TMP_ALLOC_TYPE (odds_in_composite_sieve, char);
208
209
2.02k
  for (;;)
210
2.02k
    {
211
2.02k
      unsigned long difference;
212
2.02k
      unsigned long incr, prime;
213
2.02k
      int primetest;
214
215
2.02k
      memset (composite, 0, odds_in_composite_sieve);
216
2.02k
      prime = 3;
217
3.47M
      for (i = 0; i < prime_limit; i++)
218
3.47M
        {
219
          /* Distance to next multiple of prime */
220
3.47M
          m = negative_mod_ui(p, prime);
221
          /* Only care about odd multiplies of prime. */
222
3.47M
          if (m & 1)
223
1.73M
            m += prime;
224
3.47M
          m >>= 1;
225
226
          /* Mark off any composites in sieve */
227
9.00M
          for (; m < odds_in_composite_sieve; m += prime)
228
5.52M
            composite[m] = 1;
229
3.47M
          prime += primegap[i];
230
3.47M
        }
231
232
2.02k
      difference = 0;
233
182k
      for (incr = 0; incr < odds_in_composite_sieve; difference += 2, incr += 1)
234
182k
        {
235
182k
          if (composite[incr])
236
160k
            continue;
237
238
22.4k
          increment_ui(p, p, difference);
239
22.4k
          difference = 0;
240
241
          /* Miller-Rabin test */
242
22.4k
          primetest = mpz_millerrabin (p, 25);
243
22.4k
          if (primetest)
244
2.02k
      {
245
2.02k
        TMP_FREE;
246
2.02k
        return primetest;
247
2.02k
      }
248
22.4k
        }
249
250
      /* Sieve next segment, very rare */
251
0
      increment_ui(p, p, difference);
252
0
  }
253
2.02k
}
254
255
void
256
mpz_nextprime (mpz_ptr p, mpz_srcptr n)
257
2.15k
{
258
  /* Handle negative and small numbers */
259
2.15k
  if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0)
260
128
    {
261
128
      ASSERT (NP_SMALL_LIMIT < UINT_MAX);
262
128
      mpz_set_ui (p, findnext_small (SIZ (n) > 0 ? mpz_get_ui (n) : 1, +2));
263
128
      return;
264
128
    }
265
266
  /* First odd greater than n */
267
2.02k
  mpz_add_ui (p, n, 1);
268
269
2.02k
  findnext(p, mpz_cdiv_ui, mpz_add_ui);
270
2.02k
}
271
272
int
273
mpz_prevprime (mpz_ptr p, mpz_srcptr n)
274
0
{
275
  /* Handle negative and small numbers */
276
0
  if (mpz_cmp_ui (n, 2) <= 0)
277
0
    return 0;
278
279
0
  if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0)
280
0
    {
281
0
      ASSERT (NP_SMALL_LIMIT < UINT_MAX);
282
0
      mpz_set_ui (p, findnext_small (mpz_get_ui (n), -2));
283
0
      return 2;
284
0
    }
285
286
  /* First odd less than n */
287
0
  mpz_sub_ui (p, n, 2);
288
289
0
  return findnext(p, mpz_tdiv_ui, mpz_sub_ui);
290
0
}
291