- 
                Notifications
    
You must be signed in to change notification settings  - Fork 244
 
Prime Number Functions #400
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 6 commits
4015fbc
              3ee737b
              9512bb6
              d762398
              5375a1d
              a684dbd
              3e4db8a
              dd8a61c
              4debd0d
              2a7e031
              a68910e
              386cc4d
              d79eddb
              3fdf917
              6ca245b
              7d3a520
              a1ac504
              35d2aa1
              243a299
              2eadeff
              173ce0d
              23fba36
              f7b45fd
              d687d5e
              e51d727
              1245d27
              2052081
              9f81e0d
              55ea045
              31a2105
              f545928
              d780db5
              2639bed
              94fc1ac
              6ebb906
              0521854
              b233a80
              f95c2cf
              8e2e29a
              1a24f16
              c63f1f1
              b7d4256
              fbc38c8
              2e46b81
              6759ede
              1b40403
              97244be
              fa04133
              c4a89c8
              91836f6
              6d6b19f
              81e4a6c
              0b8f1d5
              5ba0a1d
              8e240f7
              7c0cbbf
              3d9b77c
              302fb5f
              9792a23
              84a69f0
              5dc3523
              0dbe69c
              eee2c86
              f5d789a
              f2277e3
              1d2f03c
              0d9d31b
              c361cde
              66c2642
              de1f331
              eaea5f9
              e8196f3
              cb5d978
              830ccc4
              4dc3eb2
              90be100
              a772782
              2d1461f
              e7cdb32
              29eef88
              b5a28b5
              6c26b53
              980bfe7
              07e6f58
              86b9e5a
              f19149e
              1ad0d51
              5f6d06a
              670b06d
              7c7a491
              e507ba5
              c9cb41c
              e8b71a0
              d649f65
              ed98892
              c3b3934
              e9aa05d
              7c5d792
              2bbfad2
              ddc5c8a
              f517c00
              a356b47
              2212e45
              b12e2dc
              f39a4d8
              eafbefc
              cb36b89
              16c2354
              0b1a690
              8c883d1
              f357e0f
              a4f2d89
              d16e562
              91be2c3
              d9ae8c2
              7d22010
              b541987
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| // Copyright 2020 Matt Borland | ||
| // | ||
| // Use, modification and distribution are subject to the | ||
| // Boost Software License, Version 1.0. | ||
| // (See accompanying file LICENSE_1_0.txt | ||
| // or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 
     | 
||
| #ifndef BOOST_MATH_SPECIAL_FUNCTIONS_PRIME_SIEVE_HPP | ||
| #define BOOST_MATH_SPECIAL_FUNCTIONS_PRIME_SIEVE_HPP | ||
| 
     | 
||
| #include <boost/math/special_functions/prime.hpp> | ||
| #include <boost/assert.hpp> | ||
| #include <deque> | ||
| #include <vector> | ||
| #include <iterator> | ||
| #include <iostream> | ||
| 
     | 
||
| namespace boost { namespace math | ||
| { | ||
| 
     | 
||
| // https://mathworld.wolfram.com/SieveofEratosthenes.html | ||
| // https://www.cs.utexas.edu/users/misra/scannedPdf.dir/linearSieve.pdf | ||
| template<class Z, class OutputIterator> | ||
| auto prime_sieve(Z lower_bound, Z upper_bound, OutputIterator output) -> decltype(output) | ||
| { | ||
| static_assert(std::is_integral<Z>::value, "No primes for floating point types"); | ||
| BOOST_ASSERT_MSG(upper_bound + 1 < std::numeric_limits<Z>::max(), "Type Overflow"); | ||
| std::vector<Z> least_divisors(upper_bound + 1, 0); | ||
| std::deque<Z> primes; | ||
                
      
                  mborland marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| for (Z i{2}; i <= upper_bound; ++i) | ||
| { | ||
| if (least_divisors[i] == 0) | ||
| { | ||
| least_divisors[i] = i; | ||
| primes.emplace_back(i); | ||
| } | ||
                
       | 
||
| 
     | 
||
| for (size_t j{}; j < least_divisors.size(); ++j) | ||
| { | ||
| if (j >= primes.size()) | ||
| { | ||
| break; | ||
| } | ||
| 
     | 
||
| else if (primes[j] > least_divisors[i]) | ||
| { | ||
| break; | ||
| } | ||
| 
     | 
||
| else if (i * primes[j] > upper_bound) | ||
| { | ||
| break; | ||
| } | ||
| 
     | 
||
| else | ||
| { | ||
| least_divisors[i * primes[j]] = primes[j]; | ||
| } | ||
| } | ||
                
      
                  mborland marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| 
     | 
||
| auto it{primes.begin()}; | ||
| while (*it < lower_bound && it != primes.end()) | ||
| { | ||
| primes.pop_front(); | ||
| ++it; | ||
| } | ||
| 
     | 
||
| return std::move(primes.begin(), primes.end(), output); | ||
| } | ||
| 
     | 
||
| template<class Z, class OutputIterator> | ||
| auto prime_range(Z lower_bound, Z upper_bound, OutputIterator output) -> decltype(output) | ||
| { | ||
| if (upper_bound <= 104729) | ||
| { | ||
| Z i{2}; | ||
| unsigned counter {}; | ||
| std::deque<Z> primes; | ||
| while (i <= upper_bound) | ||
| { | ||
| if (i >= lower_bound) | ||
| { | ||
| primes.emplace_back(i); | ||
| } | ||
| 
     | 
||
| ++counter; | ||
| i = static_cast<Z>(boost::math::prime(counter)); | ||
| } | ||
| 
     | 
||
| return std::move(primes.begin(), primes.end(), output); | ||
| } | ||
| 
     | 
||
| else | ||
| { | ||
| return prime_sieve(lower_bound, upper_bound, output); | ||
| } | ||
| } | ||
| 
     | 
||
| template<class Z, class OutputIterator> | ||
| inline auto prime_range(Z upper_bound, OutputIterator output) -> decltype(output) | ||
| { | ||
| return prime_range(static_cast<Z>(2), upper_bound, output); | ||
| } | ||
| }} | ||
| 
     | 
||
| #endif //BOOST_MATH_SPECIAL_FUNCTIONS_PRIME_SIEVE_HPP | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| // Copyright 2020 Matt Borland | ||
| // | ||
| // Use, modification and distribution are subject to the | ||
| // Boost Software License, Version 1.0. | ||
| // (See accompanying file LICENSE_1_0.txt | ||
| // or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 
     | 
||
| #include <boost/math/special_functions/prime_sieve.hpp> | ||
| #include <benchmark/benchmark.h> | ||
| 
     | 
||
| 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)); | ||
| } | ||
| 
     | 
||
| template <typename Z> | ||
| void prime_range(benchmark::State& state) | ||
| { | ||
| Z upper = static_cast<Z>(state.range(0)); | ||
| for(auto _ : state) | ||
| { | ||
| std::vector<Z> primes; | ||
| benchmark::DoNotOptimize(boost::math::prime_range(static_cast<Z>(2), upper, std::back_inserter(primes))); | ||
| } | ||
| state.SetComplexityN(state.range(0)); | ||
| } | ||
| 
     | 
||
| template <class Z> | ||
| void prime_sieve_partial_range(benchmark::State& state) | ||
| { | ||
| Z upper = static_cast<Z>(state.range(0)); | ||
| Z lower = static_cast<Z>(state.range(0)) > 2 ? static_cast<Z>(state.range(0)) : 2; | ||
| for(auto _ : state) | ||
| { | ||
| std::vector<Z> primes; | ||
| benchmark::DoNotOptimize(boost::math::prime_sieve(lower, upper, std::back_inserter(primes))); | ||
| } | ||
| state.SetComplexityN(state.range(0)); | ||
| } | ||
| 
     | 
||
| BENCHMARK_TEMPLATE(prime_sieve, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve_partial_range, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve_partial_range, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve_partial_range, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_range, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_range, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_range, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 22)->Complexity(); | ||
| 
     | 
||
| // Direct comparison of lookup vs sieve using only range of lookup | ||
| BENCHMARK_TEMPLATE(prime_sieve, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_range, int32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_range, int64_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_sieve, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); | ||
| BENCHMARK_TEMPLATE(prime_range, uint32_t)->RangeMultiplier(2)->Range(1 << 1, 1 << 16)->Complexity(); | ||
| 
     | 
||
| BENCHMARK_MAIN(); | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| // Copyright 2020 Matt Borland | ||
| // | ||
| // Use, modification and distribution are subject to the | ||
| // Boost Software License, Version 1.0. | ||
| // (See accompanying file LICENSE_1_0.txt | ||
| // or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 
     | 
||
| #include <boost/math/special_functions/prime_sieve.hpp> | ||
| #include <boost/core/lightweight_test.hpp> | ||
| #include <boost/multiprecision/cpp_int.hpp> | ||
| #include <list> | ||
| #include <deque> | ||
| #include <array> | ||
| 
     | 
||
| template<typename Z> | ||
| void test_prime_sieve() | ||
| { | ||
| std::vector<Z> primes; | ||
| Z ref {168}; // Calculated with wolfram-alpha | ||
| 
     | 
||
| // Does the function work with a vector | ||
| boost::math::prime_sieve(2, 1000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), ref); | ||
| 
     | 
||
| // Tests for correctness | ||
| // 100 | ||
| primes.clear(); | ||
| boost::math::prime_sieve(2, 100, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), 25); | ||
| 
     | 
||
| // 10'000 | ||
| primes.clear(); | ||
| boost::math::prime_sieve(2, 10000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), 1229); | ||
| 
     | 
||
| // 100'000 | ||
| primes.clear(); | ||
| boost::math::prime_sieve(2, 100000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), 9592); | ||
| 
     | 
||
| // 1'000'000 | ||
| primes.clear(); | ||
| boost::math::prime_sieve(2, 1000000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), 78498); | ||
| 
     | 
||
| // Does the function work with a list? | ||
| std::list<Z> l_primes; | ||
| boost::math::prime_sieve(2, 1000, std::back_inserter(l_primes)); | ||
| BOOST_TEST_EQ(l_primes.size(), ref); | ||
| 
     | 
||
| // Does the function work with a deque? | ||
| std::deque<Z> d_primes; | ||
| boost::math::prime_sieve(2, 1000, std::back_inserter(d_primes)); | ||
| BOOST_TEST_EQ(d_primes.size(), ref); | ||
| } | ||
| 
     | 
||
| template<typename Z> | ||
| void test_prime_range() | ||
| { | ||
| std::vector<Z> primes; | ||
| Z ref {168}; // Calculated with wolfram-alpha | ||
| 
     | 
||
| // Does the upper and lower bound call work | ||
| boost::math::prime_range(2, 1000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), ref); | ||
| 
     | 
||
| // Does the upper bound call work | ||
| primes.clear(); | ||
| boost::math::prime_range(1000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), ref); | ||
| 
     | 
||
| // Does it work with a deque? | ||
| std::deque<Z> d_primes; | ||
| boost::math::prime_range(1000, std::back_inserter(d_primes)); | ||
| BOOST_TEST_EQ(d_primes.size(), ref); | ||
| 
     | 
||
| // Does it work with a list? | ||
| std::list<Z> l_primes; | ||
| boost::math::prime_range(1000, std::front_inserter(l_primes)); | ||
| BOOST_TEST_EQ(l_primes.size(), ref); | ||
| 
     | 
||
| // Does the lower bound change the results? | ||
| ref = 143; // Calculated with wolfram-alpha | ||
| primes.clear(); | ||
| boost::math::prime_range(100, 1000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), ref); | ||
| 
     | 
||
| // Does it work with 0 difference? | ||
| primes.clear(); | ||
| boost::math::prime_range(2, 2, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), 1); | ||
| 
     | 
||
| // Will it call the sieve for large input | ||
| ref = 78498; // Calculated with wolfram-alpha | ||
| primes.clear(); | ||
| boost::math::prime_range(1000000, std::back_inserter(primes)); | ||
| BOOST_TEST_EQ(primes.size(), ref); | ||
| } | ||
| 
     | 
||
| template<typename Z> | ||
| void test_prime_sieve_overflow() | ||
| { | ||
| std::vector<Z> primes; | ||
| 
     | 
||
| // Should die with call to BOOST_ASSERT | ||
| boost::math::prime_sieve(static_cast<Z>(2), static_cast<Z>(std::numeric_limits<Z>::max()), | ||
| std::back_inserter(primes)); | ||
| } | ||
| 
     | 
||
| int main() | ||
| { | ||
| test_prime_sieve<int>(); | ||
| test_prime_sieve<int32_t>(); | ||
| test_prime_sieve<int64_t>(); | ||
| test_prime_sieve<uint32_t>(); | ||
| 
     | 
||
| test_prime_range<int>(); | ||
| test_prime_range<int32_t>(); | ||
| test_prime_range<int64_t>(); | ||
| test_prime_range<uint32_t>(); | ||
| 
     | 
||
| test_prime_sieve<boost::multiprecision::cpp_int>(); | ||
| 
     | 
||
| //test_prime_sieve_overflow<int16_t>(); | ||
| 
     | 
||
| boost::report_errors(); | ||
| } | 
Uh oh!
There was an error while loading. Please reload this page.