Skip to content

Commit

Permalink
Use static PreSieve lookup tables
Browse files Browse the repository at this point in the history
  • Loading branch information
kimwalisch committed Nov 8, 2024
1 parent 458e3fb commit 10aee48
Show file tree
Hide file tree
Showing 18 changed files with 10,960 additions and 389 deletions.
5 changes: 1 addition & 4 deletions include/primesieve/Erat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

namespace primesieve {

class PreSieve;
class MemoryPool;

/// The abstract Erat class sieves primes using the segmented sieve
Expand All @@ -49,17 +48,15 @@ class Erat
Vector<uint8_t> sieve_;
Erat() = default;
Erat(uint64_t, uint64_t);
void init(uint64_t, uint64_t, uint64_t, PreSieve&, MemoryPool& memoryPool);
void init(uint64_t, uint64_t, uint64_t, MemoryPool& memoryPool);
void addSievingPrime(uint64_t);
NOINLINE void sieveSegment();
bool hasNextSegment() const;
static uint64_t nextPrime(uint64_t, uint64_t);

private:
uint64_t maxPreSieve_ = 0;
uint64_t maxEratSmall_ = 0;
uint64_t maxEratMedium_ = 0;
PreSieve* preSieve_ = nullptr;
EratSmall eratSmall_;
EratBig eratBig_;
EratMedium eratMedium_;
Expand Down
9 changes: 3 additions & 6 deletions include/primesieve/IteratorHelper.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///
/// @file IteratorHelper.hpp
///
/// Copyright (C) 2023 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -11,7 +11,6 @@
#define ITERATOR_HELPER_HPP

#include "PrimeGenerator.hpp"
#include "PreSieve.hpp"
#include "macros.hpp"
#include "Vector.hpp"

Expand Down Expand Up @@ -48,22 +47,20 @@ struct IteratorData
}

void newPrimeGenerator(uint64_t start,
uint64_t stop,
PreSieve& preSieve)
uint64_t stop)
{
// We use placement new to put the PrimeGenerator
// into an existing buffer. This way we don't
// need to allocate any new memory.
ASSERT(primeGenerator == nullptr);
primeGenerator = new (primeGeneratorBuffer) PrimeGenerator(start, stop, preSieve);
primeGenerator = new (primeGeneratorBuffer) PrimeGenerator(start, stop);
}

uint64_t stop;
uint64_t dist = 0;
bool include_start_number = true;
PrimeGenerator* primeGenerator = nullptr;
Vector<uint64_t> primes;
PreSieve preSieve;
alignas(PrimeGenerator) char primeGeneratorBuffer[sizeof(PrimeGenerator)];
};

Expand Down
30 changes: 11 additions & 19 deletions include/primesieve/PreSieve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
/// from them at initialization. Each buffer is assigned
/// different primes, for example:
///
/// Buffer 0 removes multiplies of: { 7, 67, 71 }
/// Buffer 1 removes multiplies of: { 11, 41, 73 }
/// Buffer 2 removes multiplies of: { 13, 43, 59 }
/// Buffer 3 removes multiplies of: { 17, 37, 53 }
/// Buffer 4 removes multiplies of: { 19, 29, 61 }
/// Buffer 5 removes multiplies of: { 23, 31, 47 }
/// Buffer 6 removes multiplies of: { 79, 97 }
/// Buffer 7 removes multiplies of: { 83, 89 }
/// buffer[0] removes multiplies of: { 7, 67, 71 } // 32 KiB
/// buffer[1] removes multiplies of: { 11, 41, 73 } // 32 KiB
/// buffer[2] removes multiplies of: { 13, 43, 59 } // 32 KiB
/// buffer[3] removes multiplies of: { 17, 37, 53 } // 32 KiB
/// buffer[4] removes multiplies of: { 19, 29, 61 } // 32 KiB
/// buffer[5] removes multiplies of: { 23, 31, 47 } // 32 KiB
/// buffer[6] removes multiplies of: { 79, 97 } // 8 KiB
/// buffer[7] removes multiplies of: { 83, 89 } // 7 KiB
///
/// Then whilst sieving, we perform a bitwise AND on the
/// buffers_ arrays and store the result in the sieve array.
/// Pre-sieving provides a speedup of up to 30% when
/// sieving the primes < 10^10 using primesieve.
///
/// Copyright (C) 2023 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -37,16 +37,8 @@ namespace primesieve {
class PreSieve
{
public:
void init(uint64_t start, uint64_t stop);
void preSieve(Vector<uint8_t>& sieve, uint64_t segmentLow) const;
uint64_t getMaxPrime() const { return maxPrime_; }
private:
uint64_t maxPrime_ = 13;
uint64_t totalDist_ = 0;
Array<Vector<uint8_t>, 8> buffers_;
void initBuffers();
static void preSieveSmall(Vector<uint8_t>& sieve, uint64_t segmentLow);
void preSieveLarge(Vector<uint8_t>& sieve, uint64_t segmentLow) const;
static void preSieve(Vector<uint8_t>& sieve, uint64_t segmentLow);
static uint64_t getMaxPrime() { return 97; }
};

} // namespace
Expand Down
10,868 changes: 10,868 additions & 0 deletions include/primesieve/PreSieve_Tables.hpp

Large diffs are not rendered by default.

5 changes: 1 addition & 4 deletions include/primesieve/PrimeGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@

namespace primesieve {

class PreSieve;

class PrimeGenerator : public Erat
{
public:
PrimeGenerator(uint64_t start, uint64_t stop, PreSieve& preSieve);
PrimeGenerator(uint64_t start, uint64_t stop);
void fillPrevPrimes(Vector<uint64_t>& primes, std::size_t* size);
static uint64_t maxCachedPrime();

Expand Down Expand Up @@ -82,7 +80,6 @@ class PrimeGenerator : public Erat
uint64_t low_ = 0;
uint64_t prime_ = 0;
uint64_t sieveIdx_ = ~0ull;
PreSieve& preSieve_;
MemoryPool memoryPool_;
SievingPrimes sievingPrimes_;
std::size_t getStartIdx() const;
Expand Down
6 changes: 1 addition & 5 deletions include/primesieve/PrimeSieve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// sieving. It is used for printing and counting primes
/// and for computing the nth prime.
///
/// Copyright (C) 2023 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -13,9 +13,7 @@
#ifndef PRIMESIEVE_CLASS_HPP
#define PRIMESIEVE_CLASS_HPP

#include "PreSieve.hpp"
#include "Vector.hpp"

#include <stdint.h>

namespace primesieve {
Expand Down Expand Up @@ -52,7 +50,6 @@ class PrimeSieve
uint64_t getDistance() const;
int getSieveSize() const;
double getSeconds() const;
PreSieve& getPreSieve();
// Setters
void setStart(uint64_t);
void setStop(uint64_t);
Expand Down Expand Up @@ -107,7 +104,6 @@ class PrimeSieve
int sieveSize_ = 0;
/// Status updates must be synchronized by main thread
ParallelSieve* parent_ = nullptr;
PreSieve preSieve_;
void processSmallPrimes();
static void printStatus(double, double);
};
Expand Down
7 changes: 3 additions & 4 deletions include/primesieve/SievingPrimes.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///
/// @file SievingPrimes.hpp
///
/// Copyright (C) 2023 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -18,15 +18,14 @@

namespace primesieve {

class PreSieve;
class MemoryPool;

class SievingPrimes : public Erat
{
public:
SievingPrimes() = default;
SievingPrimes(Erat*, uint64_t, PreSieve&, MemoryPool& memoryPool);
void init(Erat*, uint64_t, PreSieve&, MemoryPool& memoryPool);
SievingPrimes(Erat*, uint64_t, MemoryPool& memoryPool);
void init(Erat*, uint64_t, MemoryPool& memoryPool);
uint64_t next();
private:
uint64_t i_ = 0;
Expand Down
6 changes: 3 additions & 3 deletions include/primesieve/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* Furthermore primesieve_iterator.is_error is initialized
* to 0 and set to 1 if any error occurs.
*
* Copyright (C) 2023 Kim Walisch, <[email protected]>
* Copyright (C) 2024 Kim Walisch, <[email protected]>
*
* This file is distributed under the BSD License. See the COPYING
* file in the top level directory.
Expand Down Expand Up @@ -79,9 +79,9 @@ void primesieve_free_iterator(primesieve_iterator* it);
/**
* Reset the start number to 0 and free most memory.
* Keeps some smaller data structures in memory
* (e.g. the PreSieve object) that are useful if the
* (e.g. the IteratorData object) that are useful if the
* primesieve_iterator is reused. The remaining memory
* uses at most 200 kilobytes.
* uses at most 2 kilobytes.
*/
void primesieve_clear(primesieve_iterator* it);

Expand Down
6 changes: 3 additions & 3 deletions include/primesieve/iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// @brief primesieve::iterator allows to easily iterate (forwards
/// and backwards) over prime numbers.
///
/// Copyright (C) 2023 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand Down Expand Up @@ -87,9 +87,9 @@ struct iterator

/// Reset the start number to 0 and free most memory.
/// Keeps some smaller data structures in memory
/// (e.g. the PreSieve object) that are useful if the
/// (e.g. the IteratorData object) that are useful if the
/// primesieve::iterator is reused. The remaining memory
/// uses at most 200 kilobytes.
/// uses at most 2 kilobytes.
///
void clear() noexcept;

Expand Down
8 changes: 3 additions & 5 deletions src/CountPrintPrimes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// to reconstruct primes and prime k-tuplets from 1 bits of
/// the sieve array.
///
/// Copyright (C) 2022 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -18,7 +18,6 @@
#include <primesieve/littleendian_cast.hpp>
#include <primesieve/macros.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve/PreSieve.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/SievingPrimes.hpp>

Expand Down Expand Up @@ -52,8 +51,7 @@ CountPrintPrimes::CountPrintPrimes(PrimeSieve& ps) :
uint64_t sieveSize = ps.getSieveSize();
start = std::max<uint64_t>(start, 7);

ps.getPreSieve().init(start, stop);
Erat::init(start, stop, sieveSize, ps.getPreSieve(), memoryPool_);
Erat::init(start, stop, sieveSize, memoryPool_);

if (ps_.isCountkTuplets())
initCounts();
Expand Down Expand Up @@ -84,7 +82,7 @@ void CountPrintPrimes::initCounts()
void CountPrintPrimes::sieve()
{
uint64_t sieveSize = ps_.getSieveSize();
SievingPrimes sievingPrimes(this, sieveSize, ps_.getPreSieve(), memoryPool_);
SievingPrimes sievingPrimes(this, sieveSize, memoryPool_);
uint64_t prime = sievingPrimes.next();

while (hasNextSegment())
Expand Down
10 changes: 3 additions & 7 deletions src/Erat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// @brief The Erat class manages prime sieving using the
/// EratSmall, EratMedium, EratBig classes.
///
/// Copyright (C) 2023 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand Down Expand Up @@ -57,12 +57,10 @@ Erat::Erat(uint64_t start, uint64_t stop) :
/// @start: Sieve primes >= start.
/// @stop: Sieve primes <= stop.
/// @maxSieveSize: Maximum sieve array size in kilobytes.
/// @preSieve: Pre-sieve small primes.
///
void Erat::init(uint64_t start,
uint64_t stop,
uint64_t maxSieveSize,
PreSieve& preSieve,
MemoryPool& memoryPool)
{
if_unlikely(start > stop ||
Expand All @@ -75,8 +73,6 @@ void Erat::init(uint64_t start,

start_ = start;
stop_ = stop;
preSieve_ = &preSieve;
maxPreSieve_ = preSieve_->getMaxPrime();

// Convert KiB to bytes
maxSieveSize <<= 10;
Expand Down Expand Up @@ -194,7 +190,7 @@ void Erat::initAlgorithms(uint64_t maxSieveSize,
ASSERT(sieveSize % sizeof(uint64_t) == 0);
sieve_.resize(sieveSize);

if (sqrtStop > maxPreSieve_)
if (sqrtStop > PreSieve::getMaxPrime())
eratSmall_.init(stop_, l1CacheSize, maxEratSmall_);
if (sqrtStop > maxEratSmall_)
eratMedium_.init(stop_, maxEratMedium_, memoryPool);
Expand Down Expand Up @@ -258,7 +254,7 @@ void Erat::sieveLastSegment()
///
void Erat::preSieve()
{
preSieve_->preSieve(sieve_, segmentLow_);
PreSieve::preSieve(sieve_, segmentLow_);

// unset bits < start
if (segmentLow_ <= start_)
Expand Down
10 changes: 0 additions & 10 deletions src/ParallelSieve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,6 @@ void ParallelSieve::sieve()
auto task = [&]()
{
PrimeSieve ps(this);

// To improve load balancing each thread sieves many small
// intervals. For small intervals only basic pre-sieving
// is used by default to avoid initialization overhead.
// However here we know that many intervals will be sieved
// and hence there is no initialization overhead issue.
// Therefore we manually initialize pre-sieving.
PreSieve& preSieve = ps.getPreSieve();
preSieve.init(0, dist / threads);

uint64_t i;
counts_t counts;
counts.fill(0);
Expand Down
Loading

0 comments on commit 10aee48

Please sign in to comment.