File Coverage

ramanujan_primes.c
Criterion Covered Total %
statement 173 199 86.9
branch 170 264 64.3
condition n/a
subroutine n/a
pod n/a
total 343 463 74.0


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4              
5             #define FUNC_log2floor 1
6             #define FUNC_is_prime_in_sieve 1
7             #include "ptypes.h"
8             #include "sieve.h"
9             #include "util.h"
10             #include "prime_counts.h"
11             #include "inverse_interpolate.h"
12             #include "ramanujan_primes.h"
13              
14             /******************************************************************************/
15             /* RAMANUJAN PRIMES */
16             /******************************************************************************/
17              
18             static const uint8_t small_ram_primes[] = {
19             2,11,17,29,41,47,59,67,71,97,101,107,127,149,151,167,179,181,227,229,233,239,241
20             };
21             #define NSMALL_RAM (sizeof(small_ram_primes)/sizeof(small_ram_primes[0]))
22              
23             #define FAST_SMALL_NTH(n) \
24             if (n <= NSMALL_RAM) \
25             { return (n == 0) ? 0 : small_ram_primes[n-1]; }
26             #define FAST_SMALL_COUNT(n) \
27             if (n <= small_ram_primes[NSMALL_RAM-1]) { \
28             UV i; \
29             for (i = 0; i < NSMALL_RAM; i++) \
30             if (n < small_ram_primes[i]) break; \
31             return i; \
32             }
33              
34              
35             /******************************* Bounds *******************************/
36              
37             /* Upper and lower bounds done using Axler 2017:
38             * https://arxiv.org/pdf/1711.04588.pdf
39             * The parameter values have been computed using exact nth_prime,
40             * so does not depend on the nth_prime_upper / nth_prime_lower method.
41             */
42              
43 418           UV nth_ramanujan_prime_upper(UV n) {
44 418           long double R = 0, D = 0.565;
45              
46 418 100         FAST_SMALL_NTH(n);
    50          
47              
48 381 100         if (n < 12581) {
49 359 100         if (n < 168) R = ramanujan_axler(n, -4.7691, -6.2682);
50 10 100         else if (n < 2290) R = ramanujan_axler(n, -0.9315, -0.5635);
51 2 100         else if (n < 5225) R = ramanujan_axler(n, -0.5318, -0.0710);
52 1 50         else if (n < 12581) R = ramanujan_axler(n, 0.1212, 0.7973);
53 359           return nth_prime_upper(R);
54             }
55 22 50         if (n < 18175) D = 0.3548;
56 22 100         else if (n < 82883) D = -0.2450;
57 12 100         else if (n < 316314) D = -0.6384;
58 10 50         else if (n < 1000001) D = -0.9353;
59 10 100         else if (n < 4000001) D = -1.1271;
60 8 50         else if (n < 16000001) D = -1.4152;
61 0 0         else if (n < 64000001) D = -1.6671;
62 0 0         else if (n < 128000001) D = -1.8855;
63 0 0         else if (n < 256000001) D = -1.9325;
64 0 0         else if (n < 384000001) D = -2.0190;
65 0 0         else if (n < 512000001) D = -2.0310;
66             else {
67 0           D = -2.0884;
68 0 0         if (n > UVCONST( 3999654659)) D = -2.235;
69             #if BITS_PER_WORD == 64
70 0 0         if (n > UVCONST( 84086679236)) D = -2.435;
71 0 0         if (n > UVCONST( 514808375201)) D = -2.535;
72 0 0         if (n > UVCONST( 3594243587299)) D = -2.635;
73 0 0         if (n > UVCONST( 28330126673435)) D = -2.735;
74 0 0         if (n > UVCONST(117462814829787)) D = -2.8;
75             #endif
76             }
77              
78 22           return nth_prime_upper(ramanujan_axler(n, 0.0, D));
79             }
80              
81 462           UV nth_ramanujan_prime_lower(UV n) {
82 462           double R = 0, D = 0;
83              
84 462 100         FAST_SMALL_NTH(n);
    50          
85              
86 407 100         if (n < 34816) {
87 388 100         if (n < 189) R = ramanujan_axler(n, 4.2720, 0.340);
88 13 100         else if (n < 1245) R = ramanujan_axler(n, -0.2179, -6.179);
89 5 100         else if (n < 2984) R = ramanujan_axler(n, 0.1446, -4.8693);
90 4 100         else if (n < 14303) R = ramanujan_axler(n, -0.3570, -5.1154);
91 3 50         else if (n < 34816) R = ramanujan_axler(n, -1.5770, -7.5332);
92 388           return nth_prime_lower(R);
93             }
94              
95 19 100         if (n < 76400) D = 0.0126;
96 12 100         else if (n < 280816) D = 0.5132;
97 10 50         else if (n < 915887) D = 0.9967;
98 10 100         else if (n < 4000001) D = 1.5004;
99 8 50         else if (n < 16000001) D = 1.7184;
100 0 0         else if (n < 64000001) D = 1.9860;
101 0 0         else if (n < 128000001) D = 2.1352;
102 0 0         else if (n < 256000001) D = 2.1658;
103 0 0         else if (n < 384000001) D = 2.1999;
104 0 0         else if (n < 512000001) D = 2.2047;
105 0 0         else if (n < 640000001) D = 2.2324;
106             else {
107 0           D = 2.2385;
108             #if BITS_PER_WORD == 64
109 0 0         if (n > UVCONST( 14888378285)) D = 2.29;
110 0 0         if (n > UVCONST( 467037926604)) D = 2.31;
111 0 0         if (n > UVCONST( 2778491401197)) D = 2.315;
112 0 0         if (n > UVCONST( 10656144781918)) D = 2.317;
113 0 0         if (n > UVCONST( 63698770351741)) D = 2.319;
114             #endif
115             }
116              
117 19           return nth_prime_lower(ramanujan_axler(n, 1.472, D));
118             }
119              
120             /* For Ramanujan prime count bounds, use binary searches on the inverses. */
121              
122 89           UV ramanujan_prime_count_lower(UV n) {
123             UV lo, hi;
124 401 100         FAST_SMALL_COUNT(n);
    100          
    100          
125             /* We know we're between p_2n and p_3n, probably close to the former. */
126 53           lo = prime_count_lower(n)/3;
127 53           hi = prime_count_upper(n) >> 1;
128 53           return inverse_interpolate(lo, hi, n, &nth_ramanujan_prime_upper, 0);
129             }
130 89           UV ramanujan_prime_count_upper(UV n) {
131             UV lo, hi;
132 411 100         FAST_SMALL_COUNT(n);
    100          
    100          
133             /* We know we're between p_2n and p_3n, probably close to the former. */
134 54           lo = prime_count_lower(n)/3;
135 54           hi = prime_count_upper(n) >> 1;
136 54           return inverse_interpolate(lo, hi, n, &nth_ramanujan_prime_lower, 0);
137             }
138              
139             /**************************** Approximate ****************************/
140              
141 24           UV ramanujan_prime_count_approx(UV n)
142             {
143 24 50         FAST_SMALL_COUNT(n);
    0          
    0          
144             /* Extremely accurate but a bit slow */
145 24           return prime_count_approx(n) - prime_count_approx(n >> 1);
146             }
147              
148 2           UV nth_ramanujan_prime_approx(UV n)
149             {
150             UV lo, hi;
151 2 50         FAST_SMALL_NTH(n);
    0          
152             /* Interpolating using ramanujan prime count approximation */
153 2           lo = nth_ramanujan_prime_lower(n) - 1;
154 2           hi = nth_ramanujan_prime_upper(n);
155 2           return inverse_interpolate(lo, hi, n, &ramanujan_prime_count_approx, 0);
156             }
157              
158             /******************************* Arrays *******************************/
159              
160             /* Return array of first n ramanujan primes. Use Noe's algorithm. */
161 29           UV* n_ramanujan_primes(UV n) {
162             UV max, k, s, *L;
163             unsigned char* sieve;
164              
165 29 100         if (n <= NSMALL_RAM) {
166 6 50         New(0, L, n, UV);
167 39 100         for (k = 0; k < n; k++)
168 33           L[k] = small_ram_primes[k];
169 6           return L;
170             }
171              
172 23           max = nth_ramanujan_prime_upper(n); /* Rn <= max, so we can sieve to there */
173 23 50         MPUverbose(2, "sieving to %"UVuf" for first %"UVuf" Ramanujan primes\n", max, n);
174 23 50         Newz(0, L, n, UV);
175 23           L[0] = 2;
176 23           sieve = sieve_erat30(max);
177 5030 100         for (s = 0, k = 7; k <= max; k += 2) {
178 5007 100         if (is_prime_in_sieve(sieve, k)) s++;
179 5007 100         if (s < n) L[s] = k+1;
180 5007 100         if ((k & 3) == 1 && is_prime_in_sieve(sieve, (k+1)>>1)) s--;
    100          
181 5007 100         if (s < n) L[s] = k+2;
182             }
183 23           Safefree(sieve);
184 23           return L;
185             }
186              
187 155           UV* n_range_ramanujan_primes(UV nlo, UV nhi) {
188             UV mink, maxk, k, s, *L;
189              
190 155 50         if (nlo == 0) nlo = 1;
191 155 50         if (nhi == 0) nhi = 1;
192              
193             /* If we're starting from 1, just do single monolithic sieve */
194 155 100         if (nlo == 1) return n_ramanujan_primes(nhi);
195              
196 126 50         Newz(0, L, nhi-nlo+1, UV);
197 126 50         if (nlo <= 1 && nhi >= 1) L[1-nlo] = 2;
    0          
198 126 100         if (nlo <= 2 && nhi >= 2) L[2-nlo] = 11;
    50          
199 126 100         if (nhi < 3) return L;
200              
201 125           mink = nth_ramanujan_prime_lower(nlo) - 1;
202 125           maxk = nth_ramanujan_prime_upper(nhi) + 1;
203              
204 125 100         if (mink < 15) mink = 15;
205 125 100         if (mink % 2 == 0) mink--;
206 125 50         MPUverbose(2, "Rn[%"UVuf"] to Rn[%"UVuf"] Noe's: %"UVuf" to %"UVuf"\n", nlo, nhi, mink, maxk);
207              
208 125           s = 1 + prime_count(mink-2) - prime_count((mink-1)>>1);
209             {
210 125           unsigned char *segment, *seg2 = 0;
211 125           void* ctx = start_segment_primes(mink, maxk, &segment);
212 125           UV seg_base, seg_low, seg_high, new_size, seg2beg, seg2end, seg2size = 0;
213 250 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
214 125           seg2beg = 30 * (((seg_low+1)>>1)/30);
215 125           seg2end = 30 * ((((seg_high+1)>>1)+29)/30);
216 125           new_size = (seg2end - seg2beg)/30 + 1;
217 125 50         if (new_size > seg2size) {
218 125 50         if (seg2size > 0) Safefree(seg2);
219 125           New(0, seg2, new_size, unsigned char);
220 125           seg2size = new_size;
221             }
222 125           (void) sieve_segment(seg2, seg2beg/30, seg2end/30);
223 87718 100         for (k = seg_low; k <= seg_high; k += 2) {
224 87593 100         if (is_prime_in_sieve(segment, k-seg_base)) s++;
225 87593 100         if (s >= nlo && s <= nhi) L[s-nlo] = k+1;
    100          
226 87593 100         if ((k & 3) == 1 && is_prime_in_sieve(seg2, ((k+1)>>1)-seg2beg)) s--;
    100          
227 87593 100         if (s >= nlo && s <= nhi) L[s-nlo] = k+2;
    100          
228             }
229             }
230 125           end_segment_primes(ctx);
231 125           Safefree(seg2);
232             }
233 125 50         MPUverbose(2, "Generated %"UVuf" Ramanujan primes from %"UVuf" to %"UVuf"\n", nhi-nlo+1, L[0], L[nhi-nlo]);
234 125           return L;
235             }
236              
237             /* Returns array of Ram primes between low and high, results from first->last */
238 15           UV* ramanujan_primes(UV* first, UV* last, UV low, UV high)
239             {
240             UV nlo, nhi, *L, lo, hi, mid;
241              
242 15 50         if (high < 2 || high < low) return 0;
    50          
243 15 50         if (low < 2) low = 2;
244              
245 15           nlo = ramanujan_prime_count_lower(low);
246 15           nhi = ramanujan_prime_count_upper(high);
247 15           L = n_range_ramanujan_primes(nlo, nhi);
248              
249             /* Search for first entry in range */
250 50 100         for (lo = 0, hi = nhi-nlo+1; lo < hi; ) {
251 35           mid = lo + (hi-lo)/2;
252 35 100         if (L[mid] < low) lo = mid+1;
253 25           else hi = mid;
254             }
255 15           *first = lo;
256             /* Search for last entry in range */
257 38 100         for (hi = nhi-nlo+1; lo < hi; ) {
258 23           mid = lo + (hi-lo)/2;
259 23 100         if (L[mid] <= high) lo = mid+1;
260 4           else hi = mid;
261             }
262 15           *last = lo-1;
263 15           return L;
264             }
265              
266 15           UV range_ramanujan_prime_sieve(UV** list, UV lo, UV hi)
267             {
268             UV first, last, *L;
269 15           L = ramanujan_primes(&first, &last, lo, hi);
270 15 50         if (L == 0 || first > last) { *list = 0; return 0; }
    100          
271 14 100         if (first > 0)
272 8           memmove( L + 0, L + first, (last-first+1) * sizeof(UV) );
273 14           *list = L;
274 14           return last-first+1;
275             }
276              
277             /* Generate a small window of Rp's around n */
278 88           static UV* _ramanujan_prime_window(UV n, UV* winsize, UV* npos) {
279 88           UV i, v, *L, window, swin, ewin, wlen, winmult = 1;
280              
281 88 50         MPUverbose(1, "ramanujan_prime_count calculating Pi(%"UVuf")\n",n);
282 88           v = prime_count(n) - prime_count(n >> 1);
283              
284             /* For large enough n make a slightly bigger window */
285 88 50         if (n > 1000000000U) winmult = 16;
286              
287             while (1) {
288 88           window = 20 * winmult;
289 88 100         swin = (v <= window) ? 1 : v-window;
290 88           ewin = v+window;
291 88           wlen = ewin-swin+1;
292 88           L = n_range_ramanujan_primes(swin, ewin);
293 88 50         if (L[0] < n && L[wlen-1] > n) {
    50          
294             /* Naive linear search from the start. */
295 1645 50         for (i = 1; i < wlen; i++)
296 1645 100         if (L[i] > n && L[i-1] <= n)
    50          
297 88           break;
298 88 50         if (i < wlen) break;
299             }
300 0           winmult *= 2;
301 0 0         MPUverbose(1, " %s increasing window\n", "ramanujan_prime_count");
302             }
303 88           *winsize = swin;
304 88           *npos = i-1;
305 88           return L;
306             }
307              
308             /******************************* Exact *******************************/
309              
310 75           UV nth_ramanujan_prime(UV n) {
311             UV rn, *L;
312 75 100         FAST_SMALL_NTH(n);
    50          
313 52           L = n_range_ramanujan_primes(n, n);
314 52           rn = L[0];
315 52           Safefree(L);
316 52           return rn;
317             }
318              
319 984           bool is_ramanujan_prime(UV n) {
320             UV i, d, *L, swin, rn;
321             bool res;
322              
323 984 100         if (!is_prime(n)) return 0;
324 166 100         if (n < 17) return (n == 2 || n == 11);
    100          
    100          
325              
326             /* Pre-test: Check if Pi(n/2) increases before Pi(n) does. */
327 160 100         if (is_prime(n/2+1)) return 0;
328 143           d = (next_prime(n) - n)/2;
329 280 100         for (i = 2; i <= d; i++)
330 201 100         if (is_prime(n/2+i)) return 0;
331              
332             /* Very straightforward, but not the fastest method:
333             * return nth_ramanujan_prime(ramanujan_prime_count(n)) == n;
334             *
335             * Slower than below for most input sizes:
336             * L = ramanujan_primes(&beg, &end, n, n);
337             * Safefree(L);
338             * return (beg <= end);
339             */
340              
341 79           L = _ramanujan_prime_window(n, &swin, &rn);
342 79           res = (L[rn] == n);
343 79           Safefree(L);
344 79           return res;
345             }
346              
347             #if BITS_PER_WORD == 64
348             #define RAMPC2 56
349             static const UV ramanujan_counts_pow2[RAMPC2+1] = {
350             0, 1, 1, 1, 2, 4, 7, 13, 23, 42, 75, 137, 255, 463, 872, 1612,
351             3030, 5706, 10749, 20387, 38635, 73584, 140336, 268216, 513705,
352             985818, 1894120, 3645744, 7027290, 13561906, 26207278, 50697533,
353             98182656, 190335585, 369323301, 717267167,
354             UVCONST( 1394192236), UVCONST( 2712103833), UVCONST( 5279763823),
355             UVCONST( 10285641777), UVCONST( 20051180846), UVCONST( 39113482639),
356             UVCONST( 76344462797), UVCONST( 149100679004), UVCONST( 291354668495),
357             UVCONST( 569630404447), UVCONST( 1114251967767), UVCONST( 2180634225768),
358             UVCONST( 4269555883751), UVCONST( 8363243713305), UVCONST( 16388947026629),
359             UVCONST( 32129520311897), UVCONST( 63012603695171), UVCONST(123627200537929),
360             UVCONST(242637500756376), UVCONST(476379740340417), UVCONST(935609435783647) };
361             #else
362             #define RAMPC2 31 /* input limited */
363             static const UV ramanujan_counts_pow2[RAMPC2+1] = {
364             0, 1, 1, 1, 2, 4, 7, 13, 23, 42, 75, 137, 255, 463, 872, 1612,
365             3030, 5706, 10749, 20387, 38635, 73584, 140336, 268216, 513705,
366             985818, 1894120, 3645744, 7027290, 13561906, 26207278, 50697533 };
367             #endif
368              
369 12           UV ramanujan_prime_count(UV n) {
370 12 50         UV swin, rn, *L, log2 = log2floor(n);
371              
372 12 100         if ((n & (n-1)) == 0 && log2 <= RAMPC2) /* Powers of two from table */
    50          
373 1           return ramanujan_counts_pow2[log2];
374 17 100         FAST_SMALL_COUNT(n);
    100          
    50          
375              
376 9           L = _ramanujan_prime_window(n, &swin, &rn);
377 9           Safefree(L);
378 9           return swin+rn;
379             }
380              
381 10           UV ramanujan_prime_count_range(UV lo, UV hi)
382             {
383 10 50         if (hi < 2 || hi < lo) return 0;
    50          
384 10 100         return ramanujan_prime_count(hi) - ((lo <= 2) ? 0 : ramanujan_prime_count(lo-1));
385             }