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