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
|
|
|
|
|
|
|
#define FUNC_icbrt 1 |
9
|
|
|
|
|
|
|
#define FUNC_ctz 1 |
10
|
|
|
|
|
|
|
#include "util.h" |
11
|
|
|
|
|
|
|
#include "cache.h" |
12
|
|
|
|
|
|
|
#include "sieve.h" |
13
|
|
|
|
|
|
|
#include "lmo.h" |
14
|
|
|
|
|
|
|
#include "semi_primes.h" |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
#define SP_SIEVE_THRESH 100 /* When to sieve vs. iterate */ |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
/******************************************************************************/ |
19
|
|
|
|
|
|
|
/* SEMI PRIMES */ |
20
|
|
|
|
|
|
|
/******************************************************************************/ |
21
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
#define NSEMIPRIMELIST (sizeof(_semiprimelist)/sizeof(_semiprimelist[0])) |
28
|
|
|
|
|
|
|
|
29
|
113827
|
|
|
|
|
|
static UV _bs_count(UV n, UV const* const primes, UV lastidx) |
30
|
|
|
|
|
|
|
{ |
31
|
113827
|
|
|
|
|
|
UV i = 0, j = lastidx; /* primes may not start at 0 */ |
32
|
113827
|
50
|
|
|
|
|
MPUassert(n >= primes[0] && n < primes[lastidx], "prime count via binary search out of range"); |
|
|
50
|
|
|
|
|
|
33
|
2464534
|
100
|
|
|
|
|
while (i < j) { |
34
|
2350707
|
|
|
|
|
|
UV mid = i + (j-i)/2; |
35
|
2350707
|
100
|
|
|
|
|
if (primes[mid] <= n) i = mid+1; |
36
|
1502084
|
|
|
|
|
|
else j = mid; |
37
|
|
|
|
|
|
|
} |
38
|
113827
|
|
|
|
|
|
return i-1; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
2570
|
|
|
|
|
|
static UV _semiprime_count(UV n) |
42
|
|
|
|
|
|
|
{ |
43
|
2570
|
|
|
|
|
|
UV pc = 0, sum = 0, sqrtn = prev_prime(isqrt(n)+1); |
44
|
2570
|
|
|
|
|
|
UV xbeg = 0, xend = 0, xlim = 0, xoff = 0, xsize, *xarr = 0; |
45
|
2570
|
|
|
|
|
|
UV const xmax = 200000000UL; |
46
|
|
|
|
|
|
|
|
47
|
2570
|
100
|
|
|
|
|
if (n > 1000000) { /* Upfront work to speed up the many small calls */ |
48
|
12
|
|
|
|
|
|
UV nprecalc = (UV) pow(n, .75); |
49
|
12
|
100
|
|
|
|
|
if (nprecalc > _MPU_LMO_CROSSOVER) nprecalc = _MPU_LMO_CROSSOVER; |
50
|
12
|
|
|
|
|
|
prime_precalc(nprecalc); |
51
|
|
|
|
|
|
|
/* Make small calls even faster using binary search on a list */ |
52
|
12
|
|
|
|
|
|
xlim = (UV) pow(n, 0.70); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
2570
|
50
|
|
|
|
|
if (sqrtn >= 2) sum += LMO_prime_count(n/2) - pc++; |
56
|
2570
|
50
|
|
|
|
|
if (sqrtn >= 3) sum += LMO_prime_count(n/3) - pc++; |
57
|
2570
|
50
|
|
|
|
|
if (sqrtn >= 5) sum += LMO_prime_count(n/5) - pc++; |
58
|
2570
|
50
|
|
|
|
|
if (sqrtn >= 7) { |
59
|
|
|
|
|
|
|
unsigned char* segment; |
60
|
|
|
|
|
|
|
UV seg_base, seg_low, seg_high, np, cnt; |
61
|
2570
|
|
|
|
|
|
void* ctx = start_segment_primes(7, sqrtn, &segment); |
62
|
5140
|
100
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
63
|
166471
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
64
|
155985
|
|
|
|
|
|
np = n/p; |
65
|
155985
|
100
|
|
|
|
|
if (np < xlim) { |
66
|
113827
|
100
|
|
|
|
|
if (xarr == 0 || np < xbeg) { |
|
|
50
|
|
|
|
|
|
67
|
12
|
50
|
|
|
|
|
if (xarr != 0) { Safefree(xarr); xarr = 0; } |
68
|
12
|
|
|
|
|
|
xend = np; |
69
|
12
|
|
|
|
|
|
xbeg = n/sqrtn; |
70
|
12
|
50
|
|
|
|
|
if (xend - xbeg > xmax) xbeg = xend - xmax; |
71
|
12
|
|
|
|
|
|
xbeg = prev_prime(xbeg); |
72
|
12
|
|
|
|
|
|
xend = next_prime(xend); |
73
|
12
|
|
|
|
|
|
xoff = LMO_prime_count(xbeg); |
74
|
12
|
|
|
|
|
|
xarr = array_of_primes_in_range(&xsize, xbeg, xend); |
75
|
12
|
|
|
|
|
|
xend = xarr[xsize-1]; |
76
|
|
|
|
|
|
|
} |
77
|
113827
|
|
|
|
|
|
cnt = xoff + _bs_count(np, xarr, xsize-1); |
78
|
|
|
|
|
|
|
} else { |
79
|
42158
|
|
|
|
|
|
cnt = LMO_prime_count(np); |
80
|
|
|
|
|
|
|
} |
81
|
155985
|
|
|
|
|
|
sum += cnt - pc++; |
82
|
7916
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
83
|
|
|
|
|
|
|
} |
84
|
2570
|
100
|
|
|
|
|
if (xarr != 0) { Safefree(xarr); xarr = 0; } |
85
|
2570
|
|
|
|
|
|
end_segment_primes(ctx); |
86
|
|
|
|
|
|
|
} |
87
|
2570
|
|
|
|
|
|
return sum; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
/* TODO: This overflows, see p=3037000507,lo=10739422018595509581. |
91
|
|
|
|
|
|
|
* p2 = 9223372079518257049 => 9223372079518257049 + 9223372079518257049 |
92
|
|
|
|
|
|
|
* Also with lo=18446744073709551215,hi=18446744073709551515. |
93
|
|
|
|
|
|
|
*/ |
94
|
|
|
|
|
|
|
#define PGTLO(ip,p,lo) ((ip)>=(lo)) ? (ip) : ((p)*((lo)/(p)) + (((lo)%(p))?(p):0)) |
95
|
|
|
|
|
|
|
#define MARKSEMI(p,arr,lo,hi) \ |
96
|
|
|
|
|
|
|
do { UV i, p2=(p)*(p); \ |
97
|
|
|
|
|
|
|
for (i = PGTLO(p2, p, lo); i >= lo && i <= hi; i += p) arr[i-lo]++; \ |
98
|
|
|
|
|
|
|
for (i = PGTLO(2*p2, p2, lo); i >= lo && i <= hi; i += p2) arr[i-lo]++; \ |
99
|
|
|
|
|
|
|
} while (0); |
100
|
|
|
|
|
|
|
|
101
|
27
|
|
|
|
|
|
UV range_semiprime_sieve(UV** semis, UV lo, UV hi) |
102
|
|
|
|
|
|
|
{ |
103
|
27
|
|
|
|
|
|
UV *S, i, count = 0; |
104
|
|
|
|
|
|
|
|
105
|
27
|
50
|
|
|
|
|
if (lo < 4) lo = 4; |
106
|
27
|
50
|
|
|
|
|
if (hi > MPU_MAX_SEMI_PRIME) hi = MPU_MAX_SEMI_PRIME; |
107
|
|
|
|
|
|
|
|
108
|
27
|
100
|
|
|
|
|
if (hi <= _semiprimelist[NSEMIPRIMELIST-1]) { |
109
|
16
|
100
|
|
|
|
|
if (semis == 0) { |
110
|
11
|
50
|
|
|
|
|
for (i = 1; i < NSEMIPRIMELIST && _semiprimelist[i] <= hi; i++) |
|
|
100
|
|
|
|
|
|
111
|
10
|
100
|
|
|
|
|
if (_semiprimelist[i] >= lo) |
112
|
6
|
|
|
|
|
|
count++; |
113
|
|
|
|
|
|
|
} else { |
114
|
15
|
|
|
|
|
|
Newz(0, S, NSEMIPRIMELIST+1, UV); |
115
|
123
|
50
|
|
|
|
|
for (i = 1; i < NSEMIPRIMELIST && _semiprimelist[i] <= hi; i++) |
|
|
100
|
|
|
|
|
|
116
|
108
|
100
|
|
|
|
|
if (_semiprimelist[i] >= lo) |
117
|
58
|
|
|
|
|
|
S[count++] = _semiprimelist[i]; |
118
|
16
|
|
|
|
|
|
*semis = S; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
} else { |
121
|
|
|
|
|
|
|
unsigned char* nfacs; |
122
|
11
|
|
|
|
|
|
UV cutn, sqrtn = isqrt(hi); |
123
|
11
|
|
|
|
|
|
Newz(0, nfacs, hi-lo+1, unsigned char); |
124
|
11
|
50
|
|
|
|
|
if (sqrtn*sqrtn < hi && sqrtn < (UVCONST(1)<<(BITS_PER_WORD/2))-1) sqrtn++; |
|
|
50
|
|
|
|
|
|
125
|
11
|
|
|
|
|
|
cutn = (sqrtn > 30000) ? 30000 : sqrtn; |
126
|
15659
|
50
|
|
|
|
|
START_DO_FOR_EACH_PRIME(2, cutn) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
127
|
853550
|
100
|
|
|
|
|
MARKSEMI(p,nfacs,lo,hi); |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
128
|
15635
|
|
|
|
|
|
} END_DO_FOR_EACH_PRIME |
129
|
11
|
100
|
|
|
|
|
if (cutn < sqrtn) { |
130
|
|
|
|
|
|
|
unsigned char* segment; |
131
|
|
|
|
|
|
|
UV seg_base, seg_low, seg_high; |
132
|
2
|
|
|
|
|
|
void* ctx = start_segment_primes(cutn, sqrtn, &segment); |
133
|
4
|
100
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
134
|
25176
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
135
|
58489
|
50
|
|
|
|
|
MARKSEMI(p,nfacs,lo,hi); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
136
|
1155
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
137
|
|
|
|
|
|
|
} |
138
|
2
|
|
|
|
|
|
end_segment_primes(ctx); |
139
|
|
|
|
|
|
|
} |
140
|
11
|
100
|
|
|
|
|
if (semis == 0) { |
141
|
34589
|
100
|
|
|
|
|
for (i = lo; i <= hi; i++) |
142
|
34588
|
100
|
|
|
|
|
if (nfacs[i-lo] == 1) |
143
|
5802
|
|
|
|
|
|
count++; |
144
|
|
|
|
|
|
|
} else { |
145
|
10
|
|
|
|
|
|
UV cn = 50 + 1.01 * (semiprime_count_approx(hi) - semiprime_count_approx(lo)); |
146
|
10
|
50
|
|
|
|
|
New(0, S, cn, UV); |
147
|
242996
|
100
|
|
|
|
|
for (i = lo; i <= hi; i++) { |
148
|
242986
|
100
|
|
|
|
|
if (nfacs[i-lo] == 1) { |
149
|
34981
|
50
|
|
|
|
|
if (count >= cn) |
150
|
0
|
0
|
|
|
|
|
Renew(S, cn += 4000, UV); |
151
|
34981
|
|
|
|
|
|
S[count++] = i; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
} |
154
|
10
|
|
|
|
|
|
*semis = S; |
155
|
|
|
|
|
|
|
} |
156
|
11
|
|
|
|
|
|
Safefree(nfacs); |
157
|
|
|
|
|
|
|
} |
158
|
27
|
|
|
|
|
|
return count; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
|
static UV _range_semiprime_count_iterate(UV lo, UV hi) |
162
|
|
|
|
|
|
|
{ |
163
|
0
|
|
|
|
|
|
UV sum = 0; |
164
|
0
|
0
|
|
|
|
|
for (; lo < hi; lo++) /* TODO: We should walk composites */ |
165
|
0
|
0
|
|
|
|
|
if (is_semiprime(lo)) |
166
|
0
|
|
|
|
|
|
sum++; |
167
|
0
|
0
|
|
|
|
|
if (is_semiprime(hi)) |
168
|
0
|
|
|
|
|
|
sum++; |
169
|
0
|
|
|
|
|
|
return sum; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
#if 0 |
173
|
|
|
|
|
|
|
static UV _range_semiprime_selection(UV** semis, UV lo, UV hi) |
174
|
|
|
|
|
|
|
{ |
175
|
|
|
|
|
|
|
UV *S = 0, *pr, cn = 0, count = 0; |
176
|
|
|
|
|
|
|
UV i, xsize, lim = hi/2 + 1000, sqrtn = isqrt(hi); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
if (lo < 4) lo = 4; |
179
|
|
|
|
|
|
|
if (hi > MPU_MAX_SEMI_PRIME) hi = MPU_MAX_SEMI_PRIME; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
if (semis != 0) { |
182
|
|
|
|
|
|
|
cn = 50 + 1.01 * (semiprime_count_approx(hi) - semiprime_count_approx(lo)); |
183
|
|
|
|
|
|
|
New(0, S, cn, UV); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
pr = array_of_primes_in_range(&xsize, 0, lim); |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
for (i = 0; pr[i] <= sqrtn; i++) { |
189
|
|
|
|
|
|
|
UV const pi = pr[i], jlo = (lo+pi-1)/pi, jhi = hi/pi; |
190
|
|
|
|
|
|
|
UV skip, j = i; |
191
|
|
|
|
|
|
|
if (pr[j] < jlo) |
192
|
|
|
|
|
|
|
for (skip = 2048; skip > 0; skip >>= 1) |
193
|
|
|
|
|
|
|
while (j+skip-1 < xsize && pr[j+skip-1] < jlo) |
194
|
|
|
|
|
|
|
j += skip; |
195
|
|
|
|
|
|
|
if (semis == 0) { |
196
|
|
|
|
|
|
|
while (pr[j++] <= jhi) |
197
|
|
|
|
|
|
|
count++; |
198
|
|
|
|
|
|
|
} else { |
199
|
|
|
|
|
|
|
for (; pr[j] <= jhi; j++) { |
200
|
|
|
|
|
|
|
if (count >= cn) |
201
|
|
|
|
|
|
|
Renew(S, cn += 4000, UV); |
202
|
|
|
|
|
|
|
S[count++] = pi * pr[j]; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
Safefree(pr); |
207
|
|
|
|
|
|
|
if (semis != 0) { |
208
|
|
|
|
|
|
|
qsort(S, count, sizeof(UV), _numcmp); |
209
|
|
|
|
|
|
|
*semis = S; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
return count; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
#endif |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
|
217
|
16
|
|
|
|
|
|
UV semiprime_count(UV lo, UV hi) |
218
|
|
|
|
|
|
|
{ |
219
|
16
|
50
|
|
|
|
|
if (lo > hi || hi < 4) |
|
|
50
|
|
|
|
|
|
220
|
0
|
|
|
|
|
|
return 0; |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
/* tiny sizes fastest with the sieving code */ |
223
|
16
|
100
|
|
|
|
|
if (hi <= 400) return range_semiprime_sieve(0, lo, hi); |
224
|
|
|
|
|
|
|
/* Large sizes best with the prime count method */ |
225
|
15
|
100
|
|
|
|
|
if (lo <= 4) return _semiprime_count(hi); |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
/* Now it gets interesting. lo > 4, hi > 400. */ |
228
|
|
|
|
|
|
|
|
229
|
1
|
50
|
|
|
|
|
if ((hi-lo+1) < hi / (isqrt(hi)*200)) { |
230
|
0
|
0
|
|
|
|
|
MPUverbose(2, "semiprimes %"UVuf"-%"UVuf" via iteration\n", lo, hi); |
231
|
0
|
|
|
|
|
|
return _range_semiprime_count_iterate(lo,hi); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
/* TODO: Determine when _range_semiprime_selection(0,lo,hi) is better */ |
234
|
1
|
50
|
|
|
|
|
if ((hi-lo+1) < hi / (isqrt(hi)/4)) { |
235
|
1
|
50
|
|
|
|
|
MPUverbose(2, "semiprimes %"UVuf"-%"UVuf" via sieving\n", lo, hi); |
236
|
1
|
|
|
|
|
|
return range_semiprime_sieve(0, lo, hi); |
237
|
|
|
|
|
|
|
} |
238
|
0
|
0
|
|
|
|
|
MPUverbose(2, "semiprimes %"UVuf"-%"UVuf" via prime count\n", lo, hi); |
239
|
0
|
|
|
|
|
|
return _semiprime_count(hi) - _semiprime_count(lo-1); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
24
|
|
|
|
|
|
UV semiprime_count_approx(UV n) { |
243
|
24
|
100
|
|
|
|
|
if (n <= _semiprimelist[NSEMIPRIMELIST-1]) { |
244
|
1
|
|
|
|
|
|
UV i = 0; |
245
|
2
|
50
|
|
|
|
|
while (i < NSEMIPRIMELIST-1 && n >= _semiprimelist[i+1]) |
|
|
100
|
|
|
|
|
|
246
|
1
|
|
|
|
|
|
i++; |
247
|
1
|
|
|
|
|
|
return i; |
248
|
|
|
|
|
|
|
} else { |
249
|
|
|
|
|
|
|
UV lo, hi; |
250
|
23
|
|
|
|
|
|
double init, logn = log(n), loglogn = log(logn); |
251
|
|
|
|
|
|
|
/* init = n * loglogn / logn; */ |
252
|
|
|
|
|
|
|
/* init = (n/logn) * (0.11147910114 + 0.00223801350*logn + 0.44233207922*loglogn + 1.65236647896*log(loglogn)); */ |
253
|
23
|
|
|
|
|
|
init = n * (loglogn + 0.302) / logn; |
254
|
23
|
50
|
|
|
|
|
if (1.05*init >= (double)UV_MAX) |
255
|
0
|
|
|
|
|
|
return init; |
256
|
|
|
|
|
|
|
|
257
|
23
|
|
|
|
|
|
lo = 0.90 * init - 5, hi = 1.05 * init; |
258
|
563
|
100
|
|
|
|
|
while (lo < hi) { |
259
|
540
|
|
|
|
|
|
UV mid = lo + (hi-lo)/2; |
260
|
540
|
100
|
|
|
|
|
if (nth_semiprime_approx(mid) < n) lo = mid+1; |
261
|
259
|
|
|
|
|
|
else hi = mid; |
262
|
|
|
|
|
|
|
} |
263
|
23
|
|
|
|
|
|
return lo; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
3115
|
|
|
|
|
|
UV nth_semiprime_approx(UV n) { |
268
|
|
|
|
|
|
|
double logn,log2n,log3n,log4n, err_lo, err_md, err_hi, err_factor, est; |
269
|
|
|
|
|
|
|
|
270
|
3115
|
50
|
|
|
|
|
if (n < NSEMIPRIMELIST) |
271
|
0
|
|
|
|
|
|
return _semiprimelist[n]; |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
/* Piecewise with blending. Hacky and maybe overkill, but it makes |
274
|
|
|
|
|
|
|
* a big performance difference, especially at the high end. |
275
|
|
|
|
|
|
|
* Interp Range Crossover to next |
276
|
|
|
|
|
|
|
* lo 2^8 - 2^28 2^26 - 2^27 |
277
|
|
|
|
|
|
|
* md 2^25 - 2^48 2^46 - 2^47 |
278
|
|
|
|
|
|
|
* hi 2^45 - 2^64 |
279
|
|
|
|
|
|
|
*/ |
280
|
3115
|
|
|
|
|
|
logn = log(n); log2n = log(logn); log3n = log(log2n); log4n=log(log3n); |
281
|
3115
|
|
|
|
|
|
err_lo = 1.000 - 0.00018216088*logn + 0.18099609886*log2n - 0.51962474356*log3n - 0.01136143381*log4n; |
282
|
3115
|
|
|
|
|
|
err_md = 0.968 - 0.00073297945*logn + 0.09731690314*log2n - 0.25212500749*log3n - 0.01366795346*log4n; |
283
|
3115
|
|
|
|
|
|
err_hi = 0.968 - 0.00008034109*logn + 0.01522628393*log2n - 0.04020257367*log3n - 0.01266447175*log4n; |
284
|
|
|
|
|
|
|
|
285
|
3115
|
100
|
|
|
|
|
if (n <= (1UL<<26)) { |
286
|
2807
|
|
|
|
|
|
err_factor = err_lo; |
287
|
308
|
100
|
|
|
|
|
} else if (n < (1UL<<27)) { /* Linear interpolate the two in the blend area */ |
288
|
51
|
|
|
|
|
|
double x = (n - 67108864.0L) / 67108864.0L; |
289
|
51
|
|
|
|
|
|
err_factor = ((1.0L-x) * err_lo) + (x * err_md); |
290
|
257
|
100
|
|
|
|
|
} else if (logn <= 31.88477030575) { |
291
|
198
|
|
|
|
|
|
err_factor = err_md; |
292
|
59
|
50
|
|
|
|
|
} else if (logn < 32.57791748632) { |
293
|
0
|
|
|
|
|
|
double x = (n - 70368744177664.0L) / 70368744177664.0L; |
294
|
0
|
|
|
|
|
|
err_factor = ((1.0L-x) * err_md) + (x * err_hi); |
295
|
|
|
|
|
|
|
} else { |
296
|
59
|
|
|
|
|
|
err_factor = err_hi; |
297
|
|
|
|
|
|
|
} |
298
|
3115
|
|
|
|
|
|
est = 0.5 + err_factor * n * logn / log2n; |
299
|
3115
|
50
|
|
|
|
|
if (est >= UV_MAX) return 0; |
300
|
3115
|
|
|
|
|
|
return (UV)est; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
578
|
|
|
|
|
|
static UV _next_semiprime(UV n) { |
304
|
2135
|
100
|
|
|
|
|
while (!is_semiprime(++n)) |
305
|
|
|
|
|
|
|
; |
306
|
578
|
|
|
|
|
|
return n; |
307
|
|
|
|
|
|
|
} |
308
|
14233
|
|
|
|
|
|
static UV _prev_semiprime(UV n) { |
309
|
57943
|
100
|
|
|
|
|
while (!is_semiprime(--n)) |
310
|
|
|
|
|
|
|
; |
311
|
14233
|
|
|
|
|
|
return n; |
312
|
|
|
|
|
|
|
} |
313
|
2671
|
|
|
|
|
|
UV nth_semiprime(UV n) |
314
|
|
|
|
|
|
|
{ |
315
|
2671
|
|
|
|
|
|
UV guess, spcnt, sptol, gn, ming = 0, maxg = UV_MAX; |
316
|
|
|
|
|
|
|
|
317
|
2671
|
100
|
|
|
|
|
if (n < NSEMIPRIMELIST) |
318
|
116
|
|
|
|
|
|
return _semiprimelist[n]; |
319
|
|
|
|
|
|
|
|
320
|
2555
|
|
|
|
|
|
guess = nth_semiprime_approx(n); /* Initial guess */ |
321
|
2555
|
|
|
|
|
|
sptol = 16*icbrt(n); /* Guess until within this many SPs */ |
322
|
2555
|
50
|
|
|
|
|
MPUverbose(2, " using exact counts until within %"UVuf"\n",sptol); |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
/* Make successive interpolations until small enough difference */ |
325
|
2556
|
50
|
|
|
|
|
for (gn = 2; gn < 20; gn++) { |
326
|
|
|
|
|
|
|
IV adjust; |
327
|
9059
|
100
|
|
|
|
|
while (!is_semiprime(guess)) guess++; /* Guess is a semiprime */ |
328
|
2556
|
50
|
|
|
|
|
MPUverbose(2, " %"UVuf"-th semiprime is around %"UVuf" ... ", n, guess); |
329
|
|
|
|
|
|
|
/* Compute exact count at our nth-semiprime guess */ |
330
|
2556
|
|
|
|
|
|
spcnt = _semiprime_count(guess); |
331
|
2556
|
50
|
|
|
|
|
MPUverbose(2, "(%"IVdf")\n", (IV)(n-spcnt)); |
332
|
|
|
|
|
|
|
/* Stop guessing if within our tolerance */ |
333
|
2556
|
100
|
|
|
|
|
if (n==spcnt || (n>spcnt && n-spcnt < sptol) || (n
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
334
|
|
|
|
|
|
|
/* Determine how far off we think we are */ |
335
|
1
|
|
|
|
|
|
adjust = (IV) (nth_semiprime_approx(n) - nth_semiprime_approx(spcnt)); |
336
|
|
|
|
|
|
|
/* When computing new guess, ensure we don't overshoot. Rarely used. */ |
337
|
1
|
50
|
|
|
|
|
if (spcnt <= n && guess > ming) ming = guess; /* Previous guesses */ |
|
|
50
|
|
|
|
|
|
338
|
1
|
50
|
|
|
|
|
if (spcnt >= n && guess < maxg) maxg = guess; |
|
|
0
|
|
|
|
|
|
339
|
1
|
|
|
|
|
|
guess += adjust; |
340
|
1
|
50
|
|
|
|
|
if (guess <= ming || guess >= maxg) MPUverbose(2, " fix min/max for %"UVuf"\n",n); |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
341
|
1
|
50
|
|
|
|
|
if (guess <= ming) guess = ming + sptol - 1; |
342
|
1
|
50
|
|
|
|
|
if (guess >= maxg) guess = maxg - sptol + 1; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
/* If we have far enough to go, sieve for semiprimes */ |
346
|
2557
|
100
|
|
|
|
|
if (n > spcnt && (n-spcnt) > SP_SIEVE_THRESH) { /* sieve forwards */ |
|
|
100
|
|
|
|
|
|
347
|
|
|
|
|
|
|
UV *S, count, i, range; |
348
|
4
|
100
|
|
|
|
|
while (n > spcnt) { |
349
|
2
|
|
|
|
|
|
range = nth_semiprime_approx(n) - nth_semiprime_approx(spcnt); |
350
|
2
|
|
|
|
|
|
range = 1.10 * range + 100; |
351
|
2
|
50
|
|
|
|
|
if (range > guess) range = guess; /* just in case */ |
352
|
2
|
50
|
|
|
|
|
if (range > 125000000) range = 125000000; /* Not too many at a time */ |
353
|
|
|
|
|
|
|
/* Get a bunch of semiprimes */ |
354
|
2
|
50
|
|
|
|
|
MPUverbose(2, " sieving forward %"UVuf"\n", range); |
355
|
2
|
|
|
|
|
|
count = range_semiprime_sieve(&S, guess+1, guess+range); |
356
|
2
|
50
|
|
|
|
|
if (spcnt+count <= n) { |
357
|
0
|
|
|
|
|
|
guess = S[count-1]; |
358
|
0
|
|
|
|
|
|
spcnt += count; |
359
|
|
|
|
|
|
|
} else { /* Walk forwards */ |
360
|
21087
|
50
|
|
|
|
|
for (i = 0; i < count && spcnt < n; i++) { |
|
|
100
|
|
|
|
|
|
361
|
21085
|
|
|
|
|
|
guess = S[i]; |
362
|
21085
|
|
|
|
|
|
spcnt++; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
} |
365
|
2
|
|
|
|
|
|
Safefree(S); |
366
|
|
|
|
|
|
|
} |
367
|
2553
|
100
|
|
|
|
|
} else if (n < spcnt && (spcnt-n) > SP_SIEVE_THRESH) { /* sieve backwards */ |
|
|
100
|
|
|
|
|
|
368
|
|
|
|
|
|
|
UV *S, count, range; |
369
|
10
|
100
|
|
|
|
|
while (n < spcnt) { |
370
|
5
|
|
|
|
|
|
range = nth_semiprime_approx(spcnt) - nth_semiprime_approx(n); |
371
|
5
|
|
|
|
|
|
range = 1.10 * range + 100; |
372
|
5
|
50
|
|
|
|
|
if (range > guess) range = guess; /* just in case */ |
373
|
5
|
50
|
|
|
|
|
if (range > 125000000) range = 125000000; /* Not too many at a time */ |
374
|
|
|
|
|
|
|
/* Get a bunch of semiprimes */ |
375
|
5
|
50
|
|
|
|
|
MPUverbose(2, " sieving backward %"UVuf"\n", range); |
376
|
5
|
|
|
|
|
|
count = range_semiprime_sieve(&S, guess-range, guess-1); |
377
|
5
|
50
|
|
|
|
|
if (spcnt-count >= n) { |
378
|
0
|
|
|
|
|
|
guess = S[0]; |
379
|
0
|
|
|
|
|
|
spcnt -= count; |
380
|
|
|
|
|
|
|
} else { /* Walk backwards */ |
381
|
10260
|
50
|
|
|
|
|
while (count > 0 && n < spcnt) { |
|
|
100
|
|
|
|
|
|
382
|
10255
|
|
|
|
|
|
guess = S[--count]; |
383
|
10255
|
|
|
|
|
|
spcnt--; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
} |
386
|
5
|
|
|
|
|
|
Safefree(S); |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
/* Finally, iterate over semiprimes until we hit the exact spot */ |
391
|
16788
|
100
|
|
|
|
|
for (; spcnt > n; spcnt--) |
392
|
14233
|
|
|
|
|
|
guess = _prev_semiprime(guess); |
393
|
3133
|
100
|
|
|
|
|
for (; spcnt < n; spcnt++) |
394
|
578
|
|
|
|
|
|
guess = _next_semiprime(guess); |
395
|
2555
|
|
|
|
|
|
return guess; |
396
|
|
|
|
|
|
|
} |