Skip to content

Commit c3e6b06

Browse files
committed
only odd numbers in the sieve
1 parent cbe1e3c commit c3e6b06

File tree

3 files changed

+50
-36
lines changed

3 files changed

+50
-36
lines changed

cp-algo/math/sieve.hpp

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,31 @@ namespace cp_algo::math {
1717

1818
constexpr size_t base_threshold = 1 << 20;
1919

20+
constexpr auto to_ord(auto x) {
21+
return x / 2;
22+
}
23+
constexpr auto to_val(auto x) {
24+
return 2 * x + 1;
25+
}
26+
2027
const auto base_prime_bits = []() {
2128
dynamic_bit_array prime(base_threshold);
22-
prime.set_all(0xAAAAAAAAAAAAAAAA); // set all odd numbers
23-
prime.reset(1);
24-
prime.set(2);
25-
for(size_t i = 3; i * i < base_threshold; i += 2) {
26-
if (prime[i]) {
27-
for(size_t j = i * i; j < base_threshold; j += 2 * i) {
28-
prime.reset(j);
29+
prime.set_all();
30+
prime.reset(to_ord(1));
31+
for(size_t i = 3; to_ord(i * i) < base_threshold; i += 2) {
32+
if (prime[to_ord(i)]) {
33+
for(size_t j = i * i; to_ord(j) < base_threshold; j += 2 * i) {
34+
prime.reset(to_ord(j));
2935
}
3036
}
3137
}
3238
return prime;
3339
}();
3440

3541
const auto base_primes = []() {
36-
cp_algo::big_vector<uint32_t> primes = {2};
37-
for(uint32_t i = 3; i < base_threshold; i += 2) {
38-
if (base_prime_bits[i]) {
42+
cp_algo::big_vector<uint32_t> primes;
43+
for(uint32_t i = 3; to_ord(i) < base_threshold; i += 2) {
44+
if (base_prime_bits[to_ord(i)]) {
3945
primes.push_back(i);
4046
}
4147
}
@@ -48,20 +54,20 @@ namespace cp_algo::math {
4854
std::ranges::upper_bound(base_primes, sqrt_threshold)
4955
);
5056

51-
constexpr size_t max_wheel_size = 1 << 20;
57+
constexpr size_t max_wheel_size = std::min<size_t>(base_threshold, 1 << 20);
5258
struct wheel_t {
5359
dynamic_bit_array mask;
5460
uint32_t product = 1;
5561
};
5662

5763
auto make_wheel(std::vector<uint32_t> primes, uint32_t product) {
58-
assert(product % 64 == 0);
64+
assert(product % (2 * dynamic_bit_array::width) == 0);
5965
wheel_t wheel;
6066
wheel.product = product;
61-
wheel.mask.resize(product);
67+
wheel.mask.resize(product / 2);
6268
wheel.mask.set_all();
6369
for(auto p: primes) {
64-
for(size_t j = 0; j < wheel.mask.size(); j += p) {
70+
for(size_t j = to_ord(p); j < wheel.mask.size(); j += p) {
6571
wheel.mask.reset(j);
6672
}
6773
}
@@ -70,10 +76,10 @@ namespace cp_algo::math {
7076

7177
auto medium_primes = sqrt_primes;
7278
const auto wheels = []() {
73-
uint32_t product = 64;
79+
uint32_t product = 2 * dynamic_bit_array::width;
7480
std::vector<uint32_t> current;
7581
std::vector<wheel_t> wheels;
76-
for(size_t i = 1; i < size(sqrt_primes); i++) {
82+
for(size_t i = 0; i < size(sqrt_primes); i++) {
7783
uint32_t p = sqrt_primes[i];
7884
if (product * p > max_wheel_size) {
7985
if (size(current) == 1) {
@@ -82,7 +88,7 @@ namespace cp_algo::math {
8288
}
8389
wheels.push_back(make_wheel(current, product));
8490
current = {p};
85-
product = 64 * p;
91+
product = 2 * dynamic_bit_array::width * p;
8692
} else {
8793
current.push_back(p);
8894
product *= p;
@@ -93,8 +99,9 @@ namespace cp_algo::math {
9399

94100
void sieve_dense(auto &prime, uint32_t l, uint32_t r, wheel_t const& wheel) {
95101
if (l >= r) return;
96-
uint32_t wl = l / (uint32_t)dynamic_bit_array::width;
97-
uint32_t wr = r / (uint32_t)dynamic_bit_array::width + 1;
102+
const auto width = (uint32_t)dynamic_bit_array::width;
103+
uint32_t wl = l / width;
104+
uint32_t wr = (r + width - 1) / width;
98105
uint32_t N = (uint32_t)wheel.mask.words;
99106
for(uint32_t i = wl; i < wr; i += N) {
100107
auto block = std::min(N, wr - i);
@@ -119,12 +126,12 @@ namespace cp_algo::math {
119126
}();
120127

121128
constexpr uint8_t gap210[] = {
122-
10, 2, 4, 2, 4, 6, 2, 6,
123-
4, 2, 4, 6, 6, 2, 6, 4,
124-
2, 6, 4, 6, 8, 4, 2, 4,
125-
2, 4, 8, 6, 4, 6, 2, 4,
126-
6, 2, 6, 6, 4, 2, 4, 6,
127-
2, 6, 4, 2, 4, 2, 10, 2
129+
5, 1, 2, 1, 2, 3, 1, 3,
130+
2, 1, 2, 3, 3, 1, 3, 2,
131+
1, 3, 2, 3, 4, 2, 1, 2,
132+
1, 2, 4, 3, 2, 3, 1, 2,
133+
3, 1, 3, 3, 2, 1, 2, 3,
134+
1, 3, 2, 1, 2, 1, 5, 1
128135
};
129136

130137
constexpr auto state210 = []() {
@@ -150,10 +157,11 @@ namespace cp_algo::math {
150157
}
151158
}
152159

153-
// Primes smaller than N
154-
dynamic_bit_array sieve(uint32_t N) {
155-
dynamic_bit_array prime(N);
156-
prime.set_all(0xAAAAAAAAAAAAAAAA);
160+
// Primes smaller or equal than N
161+
dynamic_bit_array odd_sieve(uint32_t N) {
162+
N++;
163+
dynamic_bit_array prime(N / 2);
164+
prime.set_all();
157165
for(size_t i = 0; i < std::min(prime.words, base_prime_bits.words); i++) {
158166
prime.word(i) = base_prime_bits.word(i);
159167
}
@@ -163,19 +171,18 @@ namespace cp_algo::math {
163171
uint32_t r = std::min(start + dense_block, N);
164172
for(auto const& wheel: wheels) {
165173
auto l = start / wheel.product * wheel.product;
166-
sieve_dense(prime, l, r, wheel);
174+
sieve_dense(prime, to_ord(l), to_ord(r), wheel);
167175
}
168176
}
169177
cp_algo::checkpoint("dense sieve");
170-
171178
static constexpr uint32_t sparse_block = 1 << 21;
172179
for(uint32_t start = base_threshold; start < N; start += sparse_block) {
173180
uint32_t r = std::min(start + sparse_block, N);
174181
for(auto p: medium_primes) {
175182
if(p * p >= r) break;
176183
auto k = std::max(start / p, p);
177184
if (state210[k % 210] == 0xFF) {k += add210[k % 210];}
178-
sieve210(prime, k * p, r, p, state210[k % 210]);
185+
sieve210(prime, to_ord(k * p), to_ord(r), p, state210[k % 210]);
179186
}
180187
}
181188
cp_algo::checkpoint("sparse sieve");

cp-algo/structures/bit_array_util.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ namespace cp_algo::structures {
6767

6868
template<typename BitArray>
6969
constexpr size_t skip(BitArray const& arr, size_t pos = 0, int k = 0) {
70+
if (pos >= arr.n) return arr.n;
7071
size_t word_idx = pos / BitArray::width;
7172
auto w = arr.word(word_idx) >> (pos % BitArray::width);
7273
auto popcnt = std::popcount(w);

verify/number_theory/enumerate_primes.test.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@ using namespace cp_algo::math;
1414
void solve() {
1515
uint32_t N, A, B;
1616
cin >> N >> A >> B;
17-
auto primes = sieve(N + 1);
18-
auto cnt = count(primes, N + 1);
17+
auto primes = odd_sieve(N);
18+
auto cnt = count(primes) + (N >= 2);
1919
cp_algo::checkpoint("count");
2020
auto X = cnt < B ? 0 : (cnt - B + A - 1) / A;
2121
cout << cnt << ' ' << X << endl;
22-
for(size_t i = skip(primes, 0, B); i <= N; i = skip(primes, i, A)) {
23-
cout << i << ' ';
22+
if (X) {
23+
if (B == 0) {
24+
cout << 2 << ' ';
25+
}
26+
B = (B - 1 + A) % A;
27+
}
28+
for(size_t i = skip(primes, 0, B); i < primes.size(); i = skip(primes, i, A)) {
29+
cout << to_val(i) << ' ';
2430
}
2531
cout << "\n";
2632
cp_algo::checkpoint("print");

0 commit comments

Comments
 (0)