Quantcast
Channel: User Peter - Reinstate Monica - Stack Overflow
Viewing all articles
Browse latest Browse all 239

Answer by Peter - Reinstate Monica for Wrote a program to print prime numbers, How do I make it better?

$
0
0

I wanted to see whether it is possible to compute the primes at compile time with constexpr and give virtually instantaneous answers at run time.

I found a solution for "compile time loops" with some template magic here and modified it for this purpose. It works indeed, but compiler and other tool limits restrict the maximum number to check because the template magic unrolls the loops recursively —nested recursively in the case of pre-computing an entire list.

One obvious optimization would be to use the computed primes so far as divisors, instead of all numbers. Also, for numbers larger than CHECK_LIMIT but smaller than its square, one could use the prime numbers as divisors and be faster than a naive computation.—

Both g++ and Visual C++ need special options already for primes up to 200 (for g++-Wa,-mbig-obj and later also e.g. -ftemplate-depth=5000, for Visual C++/bigobj).

Compile times are quite long (40 seconds with g++), but the run time is "instantaneous". The executable is quite big, 13 MB with gcc and 4 MB with Visual C++.

I hope it is valuable as a proof of concept:

// Prime number compile time demo.// Uses ideas from https://artificial-mind.net/blog/2020/10/31/constexpr-for// // Needs C++20 for set::contains convenience#include <iostream>#include <set>template<long long NUM, long long DIVISOR>constexpr bool isDivisible(){    return NUM % DIVISOR == 0;}/// <summary>///  Template magic that recursively unrolls a for loop/// </summary>/// <typeparam name="F">/// The type of something to be called on each incremented loop value</typeparam>/// <typeparam name="Start"></typeparam>/// <typeparam name="End"></typeparam>/// <param name="f">What to call for each loop variable value</param>template <auto Start, auto End, class F>constexpr void constexpr_for(F&& f){    if constexpr (Start < End)    {        f(std::integral_constant<decltype(Start), Start>());        constexpr_for<Start + 1, End>(f);    }}/// <summary>Divide NUM by each number up to NUM/2 and/// <return> 0 if any division has no remainder.template <int NUM>bool isPrime(){    bool res = true;    constexpr_for<2, NUM/2+1>([&res](auto i) {        res &= !isDivisible<NUM, i>();        });    return res;}/// <summary>/// Fill a set with prime numbers up to the limit End-1/// </summary>template <int End>std::set<int> makePrimes(){    std::set<int> primes;    constexpr_for<2, End>([&primes](auto i) {        if (isPrime<i>()) primes.emplace(i);        });    return primes;}int main(){    // direct test, precomputed    std::cout << "97 is prime: " << isPrime<97>() << "\n\n";    // pre-compute during compilation (takes a few minutes with gcc,    // needs -Wa,-mbig-obj)    const int CHECK_LIMIT = 200;    std::set<int> primes = makePrimes<CHECK_LIMIT>();    for (int i = 0; i< CHECK_LIMIT; i++)    {        std::cout << i << (primes.contains(i) ? " is prime" : "") << "\n";    }}

Viewing all articles
Browse latest Browse all 239

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>