已知的最有效的尾递归素数验证函数是什么?

What's the most efficient tail recursive prime verification function known?

本文关键字:验证 函数 是什么 尾递归 有效      更新时间:2023-10-16

我一直在尝试元编程:

// compiled on Ubuntu 13.04 with:
// clang++ -O3 -ftemplate-depth-8192 -fconstexpr-depth=4096 -std=c++11 -stdlib=libc++ -lcxxrt -ldl compile-time-primes.cpp -o compile-time-primes
// assembly output with:
// clang++ -S -mllvm --x86-asm-syntax=intel -O3 -ftemplate-depth-8192 -fconstexpr-depth=4096 -std=c++11 -stdlib=libc++ -lcxxrt -ldl compile-time-primes.cpp -o compile-time-primes.asm
#include <array>
#include <iostream>
template<typename T>
constexpr bool is_prime(T number, T limit, T counter)
{
    return counter >= limit
        ? number % limit != 0
        : number % counter
            ? is_prime(number, number / counter, counter + 2)
            : false;
}
template<typename T>
constexpr bool is_prime(T n)
{
    return n == 2 || n == 3 || n == 5
        ? true
        : n <= 1 || n % 2 == 0
            ? false
            : is_prime(n, n / 3, T{3});
}
template<size_t n>
struct print_below;
template<> struct print_below<2> { inline static void primes() { std::cout << 2; } };
template<size_t n>
struct print_below
{
    inline static void primes()
    {
        print_below<n - 1>::primes();
        constexpr bool is_n_prime = is_prime(n);
        if(is_n_prime)
            std::cout << ", " << n;
    }
};
template <typename T, T... N>
struct primes { static const std::array<bool, sizeof...(N)> cache; };
template <typename T, typename L, T R>
struct append_param;
template <typename T, T... L, T R>
struct append_param<T, primes<T, L...>, R> { using primes = primes<T, L..., R>; };
template <size_t N>
struct indexer : append_param<size_t, typename indexer<N - 1>::primes, N - 1> {};
template <>
struct indexer<0> { using primes = primes<size_t>; };
template <typename T, T... N>
const std::array<bool, sizeof...(N)> primes<T, N...>::cache = {{ is_prime(N)... }};
int main()
{
    std::cout << "Some primes: n";
    print_below<8000>::primes();
    std::cout << std::endl;
    const auto &primes_cache = indexer<1000>::primes::cache;
    for(size_t i = 1; i < primes_cache.size(); ++i)
        std::cout << i << (primes_cache[i] ? " is " : " is not ") << "prime" << std::endl;
}

现在我想知道is_prime是否有更好的尾部递归算法,可以放在constexpr函数中。

还有比这更好的吗?

  • 要求:必须是尾部递归的
  • 可取:适合constexpr函数

可以。

首先,你的一个主要限制将是你的递归深度限制。对于从3sqrt(N)的每一个奇数,您的递归一次。对于~1000的递归限制,这意味着您只能处理100万以内的数字。你需要减少你所做的递归的数量

这样做的一种方法是对数字N的因子进行分治搜索。通过一些工作,您可以将其扩展到2^1000顺序的限制(即,除了递归限制之外,其他事情会使它首先无法工作)。

第二,不是检查每个奇数,而是检查6对1和5进行mod,在开始时检查2/3/5的特殊情况。除了半径为6之外,更远距离的模式也可以使用。

第三,有足够可靠的概率原数检验,使用它们是正确的答案。您可能会构建一个硬编码表,其中包含测试失败的数字,根据该表进行检查,然后以其他方式进行测试,并将上限设置为远远高于您实际可以执行的上限。

您的设计的另一个问题是,它每次测试一个素数:理想情况下,您应该建立一个素数表,并使用这些表来帮助进行素数测试。有些编译器会对之前的结果进行记忆,您可以利用这一点。