Last active
July 31, 2020 08:33
-
-
Save kimwalisch/3dc39786fab8d5b34fee to your computer and use it in GitHub Desktop.
Simple segmented sieve of Eratosthenes implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @file segmented_sieve.cpp | |
/// @author Kim Walisch, <[email protected]> | |
/// @brief This is a simple implementation of the segmented sieve of | |
/// Eratosthenes with a few optimizations. It generates the | |
/// primes below 10^9 in 0.8 seconds (single-threaded) on an | |
/// Intel Core i7-6700 3.4 GHz CPU. | |
/// @license Public domain. | |
#include <iostream> | |
#include <algorithm> | |
#include <cmath> | |
#include <vector> | |
#include <cstdlib> | |
#include <stdint.h> | |
/// Set your CPU's L1 data cache size (in bytes) here | |
const int64_t L1D_CACHE_SIZE = 32768; | |
/// Generate primes using the segmented sieve of Eratosthenes. | |
/// This algorithm uses O(n log log n) operations and O(sqrt(n)) space. | |
/// @param limit Sieve primes <= limit. | |
/// | |
void segmented_sieve(int64_t limit) | |
{ | |
int64_t sqrt = (int64_t) std::sqrt(limit); | |
int64_t segment_size = std::max(sqrt, L1D_CACHE_SIZE); | |
int64_t count = (limit < 2) ? 0 : 1; | |
// we sieve primes >= 3 | |
int64_t i = 3; | |
int64_t n = 3; | |
int64_t s = 3; | |
std::vector<char> sieve(segment_size); | |
std::vector<char> is_prime(sqrt + 1, true); | |
std::vector<int64_t> primes; | |
std::vector<int64_t> multiples; | |
for (int64_t low = 0; low <= limit; low += segment_size) | |
{ | |
std::fill(sieve.begin(), sieve.end(), true); | |
// current segment = [low, high] | |
int64_t high = low + segment_size - 1; | |
high = std::min(high, limit); | |
// generate sieving primes using simple sieve of Eratosthenes | |
for (; i * i <= high; i += 2) | |
if (is_prime[i]) | |
for (int64_t j = i * i; j <= sqrt; j += i) | |
is_prime[j] = false; | |
// initialize sieving primes for segmented sieve | |
for (; s * s <= high; s += 2) | |
{ | |
if (is_prime[s]) | |
{ | |
primes.push_back(s); | |
multiples.push_back(s * s - low); | |
} | |
} | |
// sieve the current segment | |
for (std::size_t i = 0; i < primes.size(); i++) | |
{ | |
int64_t j = multiples[i]; | |
for (int64_t k = primes[i] * 2; j < segment_size; j += k) | |
sieve[j] = false; | |
multiples[i] = j - segment_size; | |
} | |
for (; n <= high; n += 2) | |
if (sieve[n - low]) // n is a prime | |
count++; | |
} | |
std::cout << count << " primes found." << std::endl; | |
} | |
/// Usage: ./segmented_sieve n | |
/// @param n Sieve the primes up to n. | |
/// | |
int main(int argc, char** argv) | |
{ | |
if (argc >= 2) | |
segmented_sieve(std::atoll(argv[1])); | |
else | |
segmented_sieve(1000000000); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
awesome man!!! the best implementation i have seen of S seive..