@@ -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" );
0 commit comments