File Coverage

semi_primes.c
Criterion Covered Total %
statement 191 209 91.3
branch 209 288 72.5
condition n/a
subroutine n/a
pod n/a
total 400 497 80.4


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4              
5             #include "ptypes.h"
6             #include "constants.h"
7             #define FUNC_isqrt 1
8             #include "cache.h"
9             #include "sieve.h"
10             #include "util.h"
11             #include "prime_counts.h"
12             #include "inverse_interpolate.h"
13             #include "semi_primes.h"
14              
15             #define SP_SIEVE_THRESH 100 /* When to sieve vs. iterate */
16              
17             /******************************************************************************/
18             /* SEMI PRIMES */
19             /******************************************************************************/
20              
21             #if 0
22             static const unsigned char _semiprimelist[] =
23             {0,4,6,9,10,14,15,21,22,25,26,33,34,35,38,39,46,49,51,55,57,58,62,65,69,74,
24             77,82,85,86,87,91,93,94,95,106,111,115,118,119,121,122,123,129,133,134,141,
25             142,143,145,146,155,158,159,161,166,169,177,178,183,185,187,194,201,202,
26             203,205,206,209,213,214,215,217,218,219,221,226,235,237,247,249,253,254};
27             #else
28             static const unsigned short _semiprimelist[] =
29             {0,4,6,9,10,14,15,21,22,25,26,33,34,35,38,39,46,49,51,55,57,58,62,65,69,74,
30             77,82,85,86,87,91,93,94,95,106,111,115,118,119,121,122,123,129,133,134,141,
31             142,143,145,146,155,158,159,161,166,169,177,178,183,185,187,194,201,202,
32             203,205,206,209,213,214,215,217,218,219,221,226,235,237,247,249,253,254,
33             259,262,265,267,274,278,287,289,291,295,298,299,301,302,303,305,309,314,
34             319,321,323,326,327,329,334,335,339,341,346,355,358,361,362,365,371,377,
35             381,382,386,391,393,394,395,398,403,407,411,413,415,417,422,427,437,445,
36             446,447,451,453,454,458,466,469,471,473,478,481,482,485,489,493,497,501,
37             502,505,511,514,515,517,519,526,527,529,533,535,537,538,542,543,545,551,
38             553,554,559,562,565,566,573,579,581,583,586,589,591,597,611,614,622,623};
39             #endif
40             #define NSEMIPRIMELIST (sizeof(_semiprimelist)/sizeof(_semiprimelist[0]))
41              
42             #if 1
43 116227           static UV _bs_count(UV n, UV const* const primes, UV lastidx)
44             {
45 116227           UV i = 0, j = lastidx; /* primes may not start at 0 */
46 116227 50         MPUassert(n >= primes[0] && n < primes[lastidx], "prime count via binary search out of range");
    50          
47 2481178 100         while (i < j) {
48 2364951           UV mid = i + (j-i)/2;
49 2364951 100         if (primes[mid] <= n) i = mid+1;
50 1511539           else j = mid;
51             }
52 116227           return i-1;
53             }
54              
55 2467           UV semiprime_count(UV n)
56             {
57 2467           UV pc = 0, sum = 0, sqrtn = prev_prime(isqrt(n)+1);
58 2467           UV xbeg = 0, xend = 0, xlim = 0, xoff = 0, xsize = 0, *xarr = 0;
59 2467           UV const xmax = 200000000UL;
60              
61 2467 100         if (n > 1000000) { /* Upfront work to speed up the many small calls */
62 14           UV nprecalc = (UV) pow(n, .75);
63 14 100         if (nprecalc > _MPU_LMO_CROSSOVER) nprecalc = _MPU_LMO_CROSSOVER;
64 14           prime_precalc(nprecalc);
65             /* Make small calls even faster using binary search on a list */
66 14           xlim = (UV) pow(n, 0.70);
67             }
68              
69 2467 50         if (sqrtn >= 2) sum += prime_count(n/2) - pc++;
70 2467 50         if (sqrtn >= 3) sum += prime_count(n/3) - pc++;
71 2467 100         if (sqrtn >= 5) sum += prime_count(n/5) - pc++;
72 2467 100         if (sqrtn >= 7) {
73             unsigned char* segment;
74             UV seg_base, seg_low, seg_high, np, cnt;
75 2466           void* ctx = start_segment_primes(7, sqrtn, &segment);
76 4932 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
77 168431 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    50          
    100          
    100          
78 158110           np = n/p;
79 158110 100         if (np < xlim) {
80 116227 100         if (xarr == 0 || np < xbeg) {
    50          
81 14 50         if (xarr != 0) { Safefree(xarr); xarr = 0; }
82 14           xend = np;
83 14           xbeg = n/sqrtn;
84 14 50         if (xend - xbeg > xmax) xbeg = xend - xmax;
85 14           xbeg = prev_prime(xbeg);
86 14           xend = next_prime(xend);
87 14           xoff = prime_count(xbeg);
88 14           xsize = range_prime_sieve(&xarr, xbeg, xend);
89 14           xend = xarr[xsize-1];
90             }
91 116227           cnt = xoff + _bs_count(np, xarr, xsize-1);
92             } else {
93 41883           cnt = prime_count(np);
94             }
95 158110           sum += cnt - pc++;
96 7855           END_DO_FOR_EACH_SIEVE_PRIME
97             }
98 2466 100         if (xarr != 0) { Safefree(xarr); xarr = 0; }
99 2466           end_segment_primes(ctx);
100             }
101 2467           return sum;
102             }
103             #else
104              
105             /* This is much cleaner, but ends up being a little slower. */
106              
107             #include "prime_count_cache.h"
108             #define CACHED_PC(cache,n) prime_count_cache_lookup(cache,n)
109              
110             UV semiprime_count(UV n)
111             {
112             UV sum = 0, sqrtn = prev_prime(isqrt(n)+1), pc_sqrtn;
113             void *cache = prime_count_cache_create( (UV)pow(n,0.70) );
114              
115             if (sqrtn >= 2) sum += CACHED_PC(cache,n/2);
116             if (sqrtn >= 3) sum += CACHED_PC(cache,n/3);
117             if (sqrtn >= 5) sum += CACHED_PC(cache,n/5);
118             if (sqrtn >= 7) {
119             unsigned char* segment;
120             UV seg_base, seg_low, seg_high;
121             void* ctx = start_segment_primes(7, sqrtn, &segment);
122             while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
123             START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
124             sum += CACHED_PC(cache, n/p);
125             END_DO_FOR_EACH_SIEVE_PRIME
126             }
127             end_segment_primes(ctx);
128             }
129             pc_sqrtn = CACHED_PC(cache, sqrtn);
130             sum -= (pc_sqrtn * pc_sqrtn - pc_sqrtn) / 2;
131             prime_count_cache_destroy(cache);
132             return sum;
133             }
134             #endif
135              
136             /* TODO: This overflows, see p=3037000507,lo=10739422018595509581.
137             * p2 = 9223372079518257049 => 9223372079518257049 + 9223372079518257049
138             * Also with lo=18446744073709551215,hi=18446744073709551515.
139             * Using P_GT_LO_0 might help, but the biggest issue is 2*p*p overflows.
140             */
141             #define MARKSEMI(p,arr,lo,hi) \
142             do { UV i_, p2=(p)*(p); \
143             for (i_=P_GT_LO(p2, p, lo); i_ >= lo && i_ <= hi; i_ += p) arr[i_-lo]++; \
144             for (i_=P_GT_LO(2*p2, p2, lo); i_ >= lo && i_ <= hi; i_ += p2) arr[i_-lo]++; \
145             } while (0);
146              
147 31           UV range_semiprime_sieve(UV** semis, UV lo, UV hi)
148             {
149 31           UV *S, i, count = 0;
150              
151 31 50         if (lo < 4) lo = 4;
152 31 50         if (hi > MPU_MAX_SEMI_PRIME) hi = MPU_MAX_SEMI_PRIME;
153              
154 31 100         if (hi <= _semiprimelist[NSEMIPRIMELIST-1]) {
155 17 100         if (semis == 0) {
156 11 50         for (i = 1; i < NSEMIPRIMELIST && _semiprimelist[i] <= hi; i++)
    100          
157 10 100         if (_semiprimelist[i] >= lo)
158 6           count++;
159             } else {
160 16           Newz(0, S, NSEMIPRIMELIST+1, UV);
161 154 50         for (i = 1; i < NSEMIPRIMELIST && _semiprimelist[i] <= hi; i++)
    100          
162 138 100         if (_semiprimelist[i] >= lo)
163 88           S[count++] = _semiprimelist[i];
164 16           *semis = S;
165             }
166             } else {
167             unsigned char* nfacs;
168 14           UV cutn, sqrtn = isqrt(hi);
169 14           Newz(0, nfacs, hi-lo+1, unsigned char);
170 14 50         if (sqrtn*sqrtn < hi && sqrtn < (UVCONST(1)<<(BITS_PER_WORD/2))-1) sqrtn++;
    50          
171 14           cutn = (sqrtn > 30000) ? 30000 : sqrtn;
172 27523 50         START_DO_FOR_EACH_PRIME(2, cutn) {
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
173 493455 100         MARKSEMI(p,nfacs,lo,hi);
    50          
    100          
    100          
    50          
    100          
174             } END_DO_FOR_EACH_PRIME
175 14 100         if (cutn < sqrtn) {
176             unsigned char* segment;
177             UV seg_base, seg_low, seg_high;
178 6           void* ctx = start_segment_primes(cutn, sqrtn, &segment);
179 12 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
180 83292 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    50          
    100          
    100          
181 95809 100         MARKSEMI(p,nfacs,lo,hi);
    50          
    100          
    100          
    50          
    50          
182 3885           END_DO_FOR_EACH_SIEVE_PRIME
183             }
184 6           end_segment_primes(ctx);
185             }
186 14 100         if (semis == 0) {
187 44693 100         for (i = lo; i <= hi; i++)
188 44690 100         if (nfacs[i-lo] == 1)
189 7394           count++;
190             } else {
191 11           UV cn = 50 + 1.01 * (semiprime_count_approx(hi) - semiprime_count_approx(lo));
192 11 50         New(0, S, cn, UV);
193 110372 100         for (i = lo; i <= hi; i++) {
194 110361 100         if (nfacs[i-lo] == 1) {
195 15964 50         if (count >= cn)
196 0 0         Renew(S, cn += 4000, UV);
197 15964           S[count++] = i;
198             }
199             }
200 11           *semis = S;
201             }
202 14           Safefree(nfacs);
203             }
204 31           return count;
205             }
206              
207 1           static UV _range_semiprime_count_iterate(UV lo, UV hi)
208             {
209 1           UV sum = 0;
210 101 100         for (; lo < hi; lo++) /* TODO: We should walk composites */
211 100 100         if (is_semiprime(lo))
212 14           sum++;
213 1 50         if (is_semiprime(hi))
214 0           sum++;
215 1           return sum;
216             }
217              
218             #if 0
219             static UV _range_semiprime_selection(UV** semis, UV lo, UV hi)
220             {
221             UV *S = 0, *pr, cn = 0, count = 0;
222             UV i, xsize, lim = hi/2 + 1000, sqrtn = isqrt(hi);
223              
224             if (lo < 4) lo = 4;
225             if (hi > MPU_MAX_SEMI_PRIME) hi = MPU_MAX_SEMI_PRIME;
226              
227             if (semis != 0) {
228             cn = 50 + 1.01 * (semiprime_count_approx(hi) - semiprime_count_approx(lo));
229             New(0, S, cn, UV);
230             }
231              
232             xsize = range_prime_sieve(&pr, 0, lim);
233              
234             for (i = 0; pr[i] <= sqrtn; i++) {
235             UV const pi = pr[i], jlo = (lo+pi-1)/pi, jhi = hi/pi;
236             UV skip, j = i;
237             if (pr[j] < jlo)
238             for (skip = 2048; skip > 0; skip >>= 1)
239             while (j+skip-1 < xsize && pr[j+skip-1] < jlo)
240             j += skip;
241             if (semis == 0) {
242             while (pr[j++] <= jhi)
243             count++;
244             } else {
245             for (; pr[j] <= jhi; j++) {
246             if (count >= cn)
247             Renew(S, cn += 4000, UV);
248             S[count++] = pi * pr[j];
249             }
250             }
251             }
252             Safefree(pr);
253             if (semis != 0) {
254             sort_uv_array(S, count);
255             *semis = S;
256             }
257             return count;
258             }
259             #endif
260              
261              
262              
263 20           UV semiprime_count_range(UV lo, UV hi)
264             {
265 20 50         if (lo > hi || hi < 4)
    50          
266 0           return 0;
267              
268             /* tiny sizes fastest with the sieving code */
269 20 100         if (hi <= 400) return range_semiprime_sieve(0, lo, hi);
270             /* Large sizes best with the prime count method */
271 19 100         if (lo <= 4) return semiprime_count(hi);
272              
273             /* Now it gets interesting. lo > 4, hi > 400. */
274              
275 5 100         if ((hi-lo+1) < hi / ((UV)isqrt(hi)*200)) {
276 1 50         MPUverbose(2, "semiprimes %"UVuf"-%"UVuf" via iteration\n", lo, hi);
277 1           return _range_semiprime_count_iterate(lo,hi);
278             }
279             /* TODO: Determine when _range_semiprime_selection(0,lo,hi) is better */
280 4 100         if ((hi-lo+1) < hi / (isqrt(hi)/4)) {
281 3 50         MPUverbose(2, "semiprimes %"UVuf"-%"UVuf" via sieving\n", lo, hi);
282 3           return range_semiprime_sieve(0, lo, hi);
283             }
284 1 50         MPUverbose(2, "semiprimes %"UVuf"-%"UVuf" via prime count\n", lo, hi);
285 1           return semiprime_count(hi) - semiprime_count(lo-1);
286             }
287              
288 17911           UV semiprime_count_approx(UV n) {
289             UV i;
290              
291 17911 100         if (n <= _semiprimelist[NSEMIPRIMELIST-1]) {
292              
293 1971 100         for (i = 0; i < NSEMIPRIMELIST-1 && n >= _semiprimelist[i+1]; i++)
    100          
294             ;
295 13           return i;
296              
297             } else {
298              
299             /* Crisan and Erban (2020) https://arxiv.org/abs/2006.16491 */
300             UV L, res;
301 17898           double logn = log(n), loglogn = log(logn);
302 17898           double series = 0, den = 1, mc;
303             static const double C[19] = {
304             0.26149721284764278375L,
305             -2.0710850628855780875L,
306             -7.6972777412176108802L,
307             -35.345660320564161516L,
308             -206.71503925406509339L,
309             -1511.1997871316530251L,
310             -13546.323682845914021L,
311             -146229.10675883565523L,
312             -1867579.6280076650637L,
313             -27733045.258413542557L,
314             -470983423.57703294361L,
315             /*
316             * Values for C_11+ are not exact, but that's ok here.
317             * \p 80
318             * zetald(n) = { zeta'(n) / zeta(n) }
319             * zetalim(n) = { derivnum(s = 1-1e-40, zetald(s) + 1/(s-1), n-1) }
320             * B(n,x=100) = { if(n==0,return(0.2614972128476427837554268386086958590516)); (-1)^n * (sum(i=2, x, moebius(i) * i^(n-1) * derivnum(X=i,zetald(X),n-1)) + zetalim(n)) }
321             * BN = vector(20,n,B(n-1,500));
322             * C(n) = { n!*(sum(i=0,n,BN[i+1]/i!) - sum(i=1,n,1/i)) }
323             */
324             -9011500983.75L,
325             -191744069149.4L,
326             -4487573459710.5L,
327             -114472069580579.8L,
328             -3158610502077135.6L,
329             -93682567786528911.9L,
330             -2970838770257639695.3L,
331             -100274471240063911725.1L }; /* ~ C_18 */
332             /* We will use C[0] to C[L-1]. Hence L must be 19 or less. */
333             static const double CROSS[15] =
334             { 632, 9385, 136411, 4610076, 66358000, 440590000, 2557200000.0, 53032001000.0, 1151076796431.0L, 20416501389724.0L,
335             165815501587300.0L, /* Below this L = 13, Above this L = 14 */
336             953038830319448.0L, /* Cross from L = 14 to 15 */
337             20019396133340433.0L, /* Cross from L = 15 to 16 */
338             192558867109258424.0L, /* Cross from L = 16 to 17 */
339             1757883874953032448.0L }; /* Cross from L = 17 to 18 */
340              
341             static const double mincount[16] =
342             { 82, 195, 2485, 31446, 906319, 11741185, 72840337, 398702652, 7538564737.0L, 150382042176.0L, 2482510001499.0L, 19204997230933.0L, 106211451717048.0L, 2094735089989940.0L, 19282342825922188.0L, 168996486318315136.0L };
343              
344             /* Pick truncation point, note L can be one higher than the value below*/
345 40020 100         for (L = 3; L <= 17 && (double)n >= CROSS[L-3]; L++) ;
    100          
346              
347             /* Calculate truncated asymptotic value */
348 93714 100         for (i = 1; i <= L; i++) {
349 75816           series += factorial(i-1) * (loglogn / den);
350 75816           series += C[i-1] / den;
351 75816           den *= logn;
352             }
353 17898           res = (UV) ( (n / logn) * series + 0.5L );
354              
355             /* Check for overflow */
356 17898 50         if (res >= MPU_MAX_SEMI_PRIME_IDX) return MPU_MAX_SEMI_PRIME_IDX;
357              
358             /* Ensure monotonic using simple clamping */
359 17898           mc = mincount[L-3];
360             /* mc = (L == 3) ? 82 : semiprime_count_approx(CROSS[L-4]-1); */
361 17898 100         if ((double)res < mc) return mc;
362              
363 17795           return res;
364              
365             }
366             }
367              
368 2465           UV nth_semiprime_approx(UV n) {
369             double logn,log2n,log3n,log4n, err_lo, err_md, err_hi, err_factor, est;
370             UV lo, hi;
371              
372 2465 100         if (n < NSEMIPRIMELIST)
373 1           return _semiprimelist[n];
374 2464 50         if (n >= MPU_MAX_SEMI_PRIME_IDX)
375 0 0         return n == MPU_MAX_SEMI_PRIME_IDX ? MPU_MAX_SEMI_PRIME : 0;
376              
377             /* Piecewise with blending. Hacky and maybe overkill. It makes a good
378             * estimator by itself, but our count approximation is even better, so we
379             * use this as an excellent initial estimate, then use inverse binary
380             * search to lower the error another order of magnitude.
381             *
382             * Interp Range Crossover to next
383             * lo 2^8 - 2^28 2^26 - 2^27
384             * md 2^25 - 2^48 2^46 - 2^47
385             * hi 2^45 - 2^64
386             */
387              
388 2464           logn = log(n); log2n = log(logn); log3n = log(log2n); log4n=log(log3n);
389 2464           err_lo = 1.000 - 0.00018216088*logn + 0.18099609886*log2n - 0.51962474356*log3n - 0.01136143381*log4n;
390 2464           err_md = 0.968 - 0.00073297945*logn + 0.09731690314*log2n - 0.25212500749*log3n - 0.01366795346*log4n;
391 2464           err_hi = 0.968 - 0.00008034109*logn + 0.01522628393*log2n - 0.04020257367*log3n - 0.01266447175*log4n;
392              
393 2464 100         if (n <= (1UL<<26)) {
394 2445           err_factor = err_lo;
395 19 100         } else if (n < (1UL<<27)) { /* Linear interpolate the two in the blend area */
396 3           double x = (n - 67108864.0L) / 67108864.0L;
397 3           err_factor = ((1.0L-x) * err_lo) + (x * err_md);
398 16 100         } else if (logn <= 31.88477030575) {
399 14           err_factor = err_md;
400 2 50         } else if (logn < 32.57791748632) {
401 0           double x = (n - 70368744177664.0L) / 70368744177664.0L;
402 0           err_factor = ((1.0L-x) * err_md) + (x * err_hi);
403             } else {
404 2           err_factor = err_hi;
405             }
406 2464           est = err_factor * n * logn / log2n;
407 2464 50         if (est >= MPU_MAX_SEMI_PRIME) return MPU_MAX_SEMI_PRIME;
408              
409             /* Use inverse interpolation to improve the result. */
410 2464           lo = 0.979 * est - 5;
411 2464           hi = 1.03 * est;
412 2464           return inverse_interpolate(lo, hi, n, &semiprime_count_approx, 0);
413             }
414              
415 5763           static UV _next_semiprime(UV n) {
416 21122 100         while (!is_semiprime(++n))
417             ;
418 5763           return n;
419             }
420 4814           static UV _prev_semiprime(UV n) {
421 19344 100         while (!is_semiprime(--n))
422             ;
423 4814           return n;
424             }
425 2674           UV nth_semiprime(UV n)
426             {
427 2674           UV guess, spcnt, sptol, gn, ming = 0, maxg = UV_MAX;
428              
429 2674 100         if (n < NSEMIPRIMELIST)
430 226           return _semiprimelist[n];
431 2448 50         if (n >= MPU_MAX_SEMI_PRIME_IDX)
432 0 0         return n == MPU_MAX_SEMI_PRIME_IDX ? MPU_MAX_SEMI_PRIME : 0;
433              
434 2448           guess = nth_semiprime_approx(n); /* Initial guess */
435 2448           sptol = 16*icbrt(n); /* Guess until within this many SPs */
436 2448 50         MPUverbose(2, " using exact counts until within %"UVuf"\n",sptol);
437              
438             /* Make successive interpolations until small enough difference */
439 2448 50         for (gn = 2; gn < 20; gn++) {
440             IV adjust;
441 8716 100         while (!is_semiprime(guess)) guess++; /* Guess is a semiprime */
442 2448 50         MPUverbose(2, " %"UVuf"-th semiprime is around %"UVuf" ... ", n, guess);
443             /* Compute exact count at our nth-semiprime guess */
444 2448           spcnt = semiprime_count(guess);
445 2448 50         MPUverbose(2, "(%"IVdf")\n", (IV)(n-spcnt));
446             /* Stop guessing if within our tolerance */
447 2448 100         if (n==spcnt || (n>spcnt && n-spcnt < sptol) || (n
    100          
    50          
    50          
    50          
448             /* Determine how far off we think we are */
449 0           adjust = (IV) (nth_semiprime_approx(n) - nth_semiprime_approx(spcnt));
450             /* When computing new guess, ensure we don't overshoot. Rarely used. */
451 0 0         if (spcnt <= n && guess > ming) ming = guess; /* Previous guesses */
    0          
452 0 0         if (spcnt >= n && guess < maxg) maxg = guess;
    0          
453 0           guess += adjust;
454 0 0         if (guess <= ming || guess >= maxg) MPUverbose(2, " fix min/max for %"UVuf"\n",n);
    0          
    0          
455 0 0         if (guess <= ming) guess = ming + sptol - 1;
456 0 0         if (guess >= maxg) guess = maxg - sptol + 1;
457             }
458              
459             /* If we have far enough to go, sieve for semiprimes */
460 2449 100         if (n > spcnt && (n-spcnt) > SP_SIEVE_THRESH) { /* sieve forwards */
    100          
461             UV *S, count, i, range;
462 2 100         while (n > spcnt) {
463 1           range = nth_semiprime_approx(n) - nth_semiprime_approx(spcnt);
464 1           range = 1.10 * range + 100;
465 1 50         if (range > guess) range = guess; /* just in case */
466 1 50         if (range > 125000000) range = 125000000; /* Not too many at a time */
467             /* Get a bunch of semiprimes */
468 1 50         MPUverbose(2, " sieving forward %"UVuf"\n", range);
469 1           count = range_semiprime_sieve(&S, guess+1, guess+range);
470 1 50         if (spcnt+count <= n) {
471 0           guess = S[count-1];
472 0           spcnt += count;
473             } else { /* Walk forwards */
474 4122 50         for (i = 0; i < count && spcnt < n; i++) {
    100          
475 4121           guess = S[i];
476 4121           spcnt++;
477             }
478             }
479 1           Safefree(S);
480             }
481 2447 100         } else if (n < spcnt && (spcnt-n) > SP_SIEVE_THRESH) { /* sieve backwards */
    100          
482             UV *S, count, range;
483 10 100         while (n < spcnt) {
484 5           range = nth_semiprime_approx(spcnt) - nth_semiprime_approx(n);
485 5           range = 1.10 * range + 100;
486 5 50         if (range > guess) range = guess; /* just in case */
487 5 50         if (range > 125000000) range = 125000000; /* Not too many at a time */
488             /* Get a bunch of semiprimes */
489 5 50         MPUverbose(2, " sieving backward %"UVuf"\n", range);
490 5           count = range_semiprime_sieve(&S, guess-range, guess-1);
491 5 50         if (spcnt-count >= n) {
492 0           guess = S[0];
493 0           spcnt -= count;
494             } else { /* Walk backwards */
495 9709 50         while (count > 0 && n < spcnt) {
    100          
496 9704           guess = S[--count];
497 9704           spcnt--;
498             }
499             }
500 5           Safefree(S);
501             }
502             }
503              
504             /* Finally, iterate over semiprimes until we hit the exact spot */
505 7262 100         for (; spcnt > n; spcnt--)
506 4814           guess = _prev_semiprime(guess);
507 8211 100         for (; spcnt < n; spcnt++)
508 5763           guess = _next_semiprime(guess);
509 2448           return guess;
510             }