3
3
// / @brief The Erat class manages prime sieving using the
4
4
// / EratSmall, EratMedium, EratBig classes.
5
5
// /
6
- // / Copyright (C) 2024 Kim Walisch, <kim.walisch@gmail.com>
6
+ // / Copyright (C) 2025 Kim Walisch, <kim.walisch@gmail.com>
7
7
// /
8
8
// / This file is distributed under the BSD License. See the COPYING
9
9
// / file in the top level directory.
@@ -110,20 +110,34 @@ void Erat::initAlgorithms(uint64_t maxSieveSize,
110
110
uint64_t minSieveSize = std::min (l1CacheSize, maxSieveSize);
111
111
112
112
// ================================================================
113
- // 2. sieveSize = inBetween(minSieveSize, sqrtStop, maxSieveSize)
113
+ // 2. sieveSize = sqrt(stop) * FACTOR_SIEVESIZE
114
+ // ================================================================
115
+
116
+ // Using a larger FACTOR_SIEVESIZE increases the segment size
117
+ // in the sieve of Eratosthenes and hence reduces the number
118
+ // of operations used by the algorithm. However, as a drawback
119
+ // a larger segment size is less cache efficient and hence
120
+ // performance may deteriorate on CPUs with limited L2 cache
121
+ // bandwidth (especially when using multi-threading).
122
+ uint64_t sieveSize = uint64_t (sqrtStop * config::FACTOR_SIEVESIZE);
123
+
124
+ // ================================================================
125
+ // 3. L1CacheSize <= sieveSize <= L2CacheSize
114
126
// ================================================================
115
127
116
128
// For small stop numbers a small sieve array size that
117
129
// matches the CPU's L1 data cache size performs best.
118
- // For larger stop numbers a sieve array size that is
119
- // within [L1CacheSize, L2CacheSize] usually performs best.
120
- uint64_t sieveSize = inBetween (minSieveSize, sqrtStop, maxSieveSize);
130
+ // For larger stop numbers a sieve array size that is ~
131
+ // L2CacheSize usually performs best. Hence our sieve size
132
+ // increases dynamically based on the stop number but it
133
+ // can never exceed the L2CacheSize (or maxSieveSize).
134
+ sieveSize = inBetween (minSieveSize, sieveSize, maxSieveSize);
121
135
sieveSize = inBetween (16 << 10 , sieveSize, 8192 << 10 );
122
136
sieveSize = ceilDiv (sieveSize, sizeof (uint64_t )) * sizeof (uint64_t );
123
137
minSieveSize = std::min (l1CacheSize, sieveSize);
124
138
125
139
// ================================================================
126
- // 3 . Initialize upper bounds for EratSmall & EratMedium
140
+ // 4 . Initialize upper bounds for EratSmall & EratMedium
127
141
// ================================================================
128
142
129
143
// Small sieving primes are processed using the EratSmall
@@ -134,7 +148,7 @@ void Erat::initAlgorithms(uint64_t maxSieveSize,
134
148
maxEratMedium_ = (uint64_t ) (sieveSize * config::FACTOR_ERATMEDIUM);
135
149
136
150
// ================================================================
137
- // 4 . EratBig requires a power of 2 sieve size
151
+ // 5 . EratBig requires a power of 2 sieve size
138
152
// ================================================================
139
153
140
154
if (sqrtStop > maxEratMedium_)
@@ -146,14 +160,14 @@ void Erat::initAlgorithms(uint64_t maxSieveSize,
146
160
}
147
161
148
162
// ================================================================
149
- // 5 . Ensure we allocate the smallest possible amount of memory
163
+ // 6 . Ensure we allocate the smallest possible amount of memory
150
164
// ================================================================
151
165
152
166
maxEratSmall_ = std::min (maxEratSmall_, sqrtStop);
153
167
maxEratMedium_ = std::min (maxEratMedium_, sqrtStop);
154
168
155
169
// ================================================================
156
- // 6 . Initialize segment bounds
170
+ // 7 . Initialize segment bounds
157
171
// ================================================================
158
172
159
173
// The 8 bits of each byte of the sieve array correspond to
@@ -168,7 +182,7 @@ void Erat::initAlgorithms(uint64_t maxSieveSize,
168
182
segmentHigh_ = std::min (segmentHigh_, stop_);
169
183
170
184
// ================================================================
171
- // 7 . Use tiny sieveSize if possible
185
+ // 8 . Use tiny sieveSize if possible
172
186
// ================================================================
173
187
174
188
// If we are sieving just a single segment
@@ -184,7 +198,7 @@ void Erat::initAlgorithms(uint64_t maxSieveSize,
184
198
}
185
199
186
200
// ================================================================
187
- // 8 . Finally, initialize EratSmall, EratMedium & EratBig
201
+ // 9 . Finally, initialize EratSmall, EratMedium & EratBig
188
202
// ================================================================
189
203
190
204
ASSERT (sieveSize % sizeof (uint64_t ) == 0 );
0 commit comments