| 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
|
|
|
|
|
|
|
} |