From 9f81e0d9646fe652c9dbd06ea7ccf4bcdbcda522 Mon Sep 17 00:00:00 2001 From: mborland Date: Sun, 26 Jul 2020 21:54:17 -0500 Subject: [PATCH] Tests and performance compairsons [WIP][CI SKIP] --- .../math/special_functions/prime_sieve.hpp | 24 ++-- .../performance/prime_sieve_performance.cpp | 119 +++++++++++++++++- test/test_prime_sieve.cpp | 66 +++++++++- 3 files changed, 188 insertions(+), 21 deletions(-) diff --git a/include/boost/math/special_functions/prime_sieve.hpp b/include/boost/math/special_functions/prime_sieve.hpp index ab3eded9e..d06284e2a 100644 --- a/include/boost/math/special_functions/prime_sieve.hpp +++ b/include/boost/math/special_functions/prime_sieve.hpp @@ -306,22 +306,13 @@ void sub_linear_wheel_sieve(Z upper_bound, Container &resultant_primes) Z Mk {2}; Z k {3}; resultant_primes.emplace_back(static_cast(2)); - for(; true; k += 2) - { - if(is_prime(k)) - { - if(Mk * k > limit) - { - break; - } - else - { - Mk *= k; - resultant_primes.emplace_back(k); - } - } - } + while(Mk * k <= limit) + { + Mk *= k; + resultant_primes.emplace_back(k); + k += 2; + } // Initialze wheel wk std::vector wk; @@ -372,8 +363,9 @@ void sub_linear_wheel_sieve(Z upper_bound, Container &resultant_primes) } // Step 3 - Run the linear algorithm starting with p := next(S, 1), which is p_k+1 + // next(S, 1) = S[1] // 4 - A linear Algorithm - Z p {2}; + Z p {S[1]}; while(p * p <= upper_bound) { diff --git a/reporting/performance/prime_sieve_performance.cpp b/reporting/performance/prime_sieve_performance.cpp index ccfa98bd1..01afbd5f1 100644 --- a/reporting/performance/prime_sieve_performance.cpp +++ b/reporting/performance/prime_sieve_performance.cpp @@ -5,9 +5,94 @@ // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "../../include/boost/math/special_functions/prime_sieve.hpp" +//#include #include +#include +#include +// Individual Algos +// Linear +template +inline auto linear_sieve_helper(Z upper_bound, std::vector c) -> std::vector +{ + boost::math::detail::linear_sieve(upper_bound, c); + return c; +} + +template +void linear_sieve(benchmark::State& state) +{ + Z upper = static_cast(state.range(0)); + for(auto _ : state) + { + std::vector primes; + benchmark::DoNotOptimize(linear_sieve_helper(upper, primes)); + } + state.SetComplexityN(state.range(0)); +} + +template +inline auto sub_linear_sieve_helper(Z upper_bound, std::vector c) -> std::vector +{ + boost::math::detail::sub_linear_wheel_sieve(upper_bound, c); + return c; +} + +template +void sub_linear_sieve(benchmark::State& state) +{ + Z upper = static_cast(state.range(0)); + for(auto _ : state) + { + std::vector primes; + benchmark::DoNotOptimize(sub_linear_sieve_helper(upper, primes)); + } + state.SetComplexityN(state.range(0)); +} + +// Segmented +template +inline auto mask_sieve_helper(Z lower_bound, Z upper_bound, std::vector c) -> std::vector +{ + boost::math::detail::mask_sieve(lower_bound, upper_bound, c); + return c; +} + +template +void mask_sieve(benchmark::State& state) +{ + Z lower = static_cast(2); + Z upper = static_cast(state.range(0)); + for(auto _ : state) + { + std::vector primes; + benchmark::DoNotOptimize(mask_sieve_helper(lower, upper, primes)); + } + state.SetComplexityN(state.range(0)); +} + +template +inline auto segmented_wheel_sieve_helper(Z lower_bound, Z upper_bound, std::vector c) -> std::vector +{ + boost::math::detail::linear_segmented_wheel_sieve(lower_bound, upper_bound, c); + return c; +} + +template +void segmented_wheel_sieve(benchmark::State& state) +{ + Z lower = static_cast(2); + Z upper = static_cast(state.range(0)); + for(auto _ : state) + { + std::vector primes; + benchmark::DoNotOptimize(segmented_wheel_sieve_helper(lower, upper, primes)); + } + state.SetComplexityN(state.range(0)); +} + +// Complete Implementations template void prime_sieve(benchmark::State& state) { @@ -33,11 +118,39 @@ void prime_sieve_partial_range(benchmark::State& state) state.SetComplexityN(state.range(0)); } +template +void kimwalish_primes(benchmark::State& state) +{ + + Z upper = static_cast(state.range(0)); + for (auto _ : state) + { + std::vector primes; + primesieve::generate_primes(upper, &primes); + benchmark::DoNotOptimize(primes.back()); + } + state.SetComplexityN(state.range(0)); +} + +// Individual Algos + +// Linear +BENCHMARK_TEMPLATE(linear_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(benchmark::oN); +BENCHMARK_TEMPLATE(sub_linear_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); + + +// Segmented +BENCHMARK_TEMPLATE(mask_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 2, 2 << 22)->Complexity(benchmark::oNLogN); +BENCHMARK_TEMPLATE(segmented_wheel_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 2, 2 << 22)->Complexity(); + +/* +// Complete Implementations BENCHMARK_TEMPLATE(prime_sieve, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity()->UseRealTime(); -BENCHMARK_TEMPLATE(prime_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 30)->Complexity()->UseRealTime(); +BENCHMARK_TEMPLATE(prime_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 30)->Complexity(benchmark::oN)->UseRealTime(); +BENCHMARK_TEMPLATE(kimwalish_primes, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 30)->Complexity(benchmark::oN)->UseRealTime(); BENCHMARK_TEMPLATE(prime_sieve, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity()->UseRealTime(); BENCHMARK_TEMPLATE(prime_sieve_partial_range, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity()->UseRealTime(); BENCHMARK_TEMPLATE(prime_sieve_partial_range, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity()->UseRealTime(); BENCHMARK_TEMPLATE(prime_sieve_partial_range, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity()->UseRealTime(); - +*/ BENCHMARK_MAIN(); diff --git a/test/test_prime_sieve.cpp b/test/test_prime_sieve.cpp index feeb9174a..8f9c2a6b9 100644 --- a/test/test_prime_sieve.cpp +++ b/test/test_prime_sieve.cpp @@ -5,7 +5,8 @@ // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "../include/boost/math/special_functions/prime_sieve.hpp" +//#include #include #include #include @@ -23,6 +24,11 @@ void test_prime_sieve() BOOST_TEST_EQ(primes.size(), ref); // Tests for correctness + // 2 + primes.clear(); + boost::math::prime_sieve(2, std::back_inserter(primes)); + BOOST_TEST_EQ(primes.size(), 0); + // 100 primes.clear(); boost::math::prime_sieve(100, std::back_inserter(primes)); @@ -92,6 +98,51 @@ void test_prime_range() BOOST_TEST_EQ(primes.size(), ref); } +template +void test_sub_linear_prime_sieve() +{ + std::vector primes; + + // Does the function work with a vector + boost::math::detail::sub_linear_wheel_sieve(100, primes); + BOOST_TEST_EQ(primes.size(), 25); + + // 1'000 + primes.clear(); + boost::math::detail::sub_linear_wheel_sieve(1'000, primes); + BOOST_TEST_EQ(primes.size(), 168); + + // 10'000 + primes.clear(); + boost::math::detail::sub_linear_wheel_sieve(10'000, primes); + BOOST_TEST_EQ(primes.size(), 1229); +} + +template +void test_linear_segmented_sieve() +{ + std::vector primes; + + // 10 - 20: Tests only step 1 + boost::math::detail::linear_segmented_wheel_sieve(10, 20, primes); + BOOST_TEST_EQ(primes.size(), 4); + + // 100 - 200: Tests step 2 + primes.clear(); + boost::math::detail::linear_segmented_wheel_sieve(100, 200, primes); + BOOST_TEST_EQ(primes.size(), 21); + + // 100 - 1'000 + primes.clear(); + boost::math::detail::linear_segmented_wheel_sieve(100, 1'000, primes); + BOOST_TEST_EQ(primes.size(), 143); + + // 1'000 - 10'000 + primes.clear(); + boost::math::detail::linear_segmented_wheel_sieve(1'000, 10'000, primes); + BOOST_TEST_EQ(primes.size(), 1061); +} + template void test_prime_sieve_overflow() { @@ -159,6 +210,17 @@ void test_par_prime_sieve_large() int main() { + test_sub_linear_prime_sieve(); + test_sub_linear_prime_sieve(); + test_sub_linear_prime_sieve(); + test_sub_linear_prime_sieve(); + + test_linear_segmented_sieve(); + test_linear_segmented_sieve(); + test_linear_segmented_sieve(); + test_linear_segmented_sieve(); + + /* test_prime_sieve(); test_prime_sieve(); test_prime_sieve(); @@ -181,6 +243,6 @@ int main() //test_par_prime_sieve_large(); #endif - + */ boost::report_errors(); }