Prime Number Functions - #400
Conversation
|
FYI there's a Miller Rabin test in Multiprecision already. |
|
@mborland : OMG thank you; we've needed a prime sieve for so long. |
|
@mborland : I would definitely change the name from |
|
@mborland : IIRC, the Joy of Factoring also creates bitsets which set prime at bit i and has it zeroed at composites. Is this a useful API? |
|
@NAThompson That sounds like wheel factorization. That method is added to the sieve of Eratosthenes, but would not be applicable here. |
|
Would it be more ergonomic to have std::vector<int64_t> primes(1000); // gimme 1000 primes
prime_sieve(primes.begin(), primes.end());(I need to stay in my lane here; @jeremy-murphy is much better at ergonomics.) |
|
@mborland : I have begun a performance comparison with Kim Walish's prime sieve. Here is the code: #include <vector>
#include <boost/math/special_functions/prime_sieve.hpp>
#include <benchmark/benchmark.h>
#include <primesieve.hpp>
template <class Z>
void prime_sieve(benchmark::State& state)
{
Z upper = static_cast<Z>(state.range(0));
for(auto _ : state)
{
std::vector<Z> primes;
benchmark::DoNotOptimize(boost::math::prime_sieve(static_cast<Z>(2), upper, std::back_inserter(primes)));
}
state.SetComplexityN(state.range(0));
}
BENCHMARK_TEMPLATE(prime_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity();
template <class Z>
void kimwalish_primes(benchmark::State& state)
{
Z upper = static_cast<Z>(state.range(0));
for (auto _ : state)
{
std::vector<Z> primes;
primesieve::generate_primes(upper, &primes);
benchmark::DoNotOptimize(primes.back());
}
state.SetComplexityN(state.range(0));
}
BENCHMARK_TEMPLATE(kimwalish_primes, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity();
BENCHMARK_MAIN();and the results: So it looks like there is 1-2 orders of magnitude of performance improvement left in the boost implementation; presumably we need to find it. . . |
|
@NAThompson It would be fairly easy to create light wrappers to the current I will have to do some digging to see where more performance can be squeezed out. |
Nah, if it's not obviously a better way to do it, I'm not interested in it. |
|
@mborland : Also, make sure to tag your commit messages with |
|
I just went through The Joy of Factoring to refresh my memory on how these sieves work. I implemented algorithm 8.2 of that book, which the author claims runs in O(J*log(log(J)) time. He also references P.A. Pritchard who has given an algorithm which runs in O(J/log(log(J)) time; see A sublinear additive sieve for finding prime numbers, Comm. ACM 24, 1981. In any case, this is how my naive implementation of algorithm 8.2 looks: And the results: Algorithm 8.2 is actually competitive with Kim Walish for smaller N but starts to lag for larger N. |
|
@NAThompson I am seeing a similar result using a segmented sieve. Currently faster than kimwalish, and |
|
Just ran this benchmark under So Kim Walish's prime generator does indeed compute logarithms and fill up a table of primes; quite a bit of time in However if you look at the Joy of Factoring algorithm, it spends way more time in the So there are some opportunities there; you'll see that I'm only checking odd numbers after 2, there's probably some way to extend that to making the fill faster. |
|
@NAThompson I have found some performance improvements using C-style arrays instead of |
a2aedbb to
3e4db8a
Compare
|
@NAThompson This latest iteration's benchmark delivered much better results: prime_sieve<int64_t>/real_time_BigO 2.87 N 0.22 N |
|
@NAThompson This should fit the bill. Performance ticked down a bit to 3.07N/0.23N because I realized I was relying on the prime table to be statically linked. If you dynamically linked the previous implementation the performance was ~0.2NlgN. |
I do recommend that the prime table not be used at all; my own preference would be to deprecate this header once your sieve is in. |
|
@NAThompson That makes sense. I can add the notice. |
types until the max of size_t has been reached [CI SKIP]
Last known point where all composite tests pass [CI SKIP]
b541987 to
6675c43
Compare




An initial addition of two prime number functions:
prime_sieveis a linear prime sieve algorithm. Currently benchmarks O(n).prime_rangereturns all the prime numbers in the range [lower_bound, upper_bound]. For the first 1000 primes it can use the already built in lookup tables; outside of that it will callprime_sieve. This is the function intended for end users to call.Future additions would include a Miller-Rabin primality test.