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

时间:2013-06-03 01:31:43

标签: c++ mathematical-optimization variadic-templates tail-recursion constexpr

我正在尝试元编程:

// 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功能。

1 个答案:

答案 0 :(得分:2)

首先,您的一个主要限制是您的递归深度限制。对于从3sqrt(N)的每个奇数,您的一次递归。具有~1000递归限制,这意味着您只能处理高达100万的数字。你需要减少你正在进行的递归量。

执行此操作的方法是对您的号码N的因素进行分而治之搜索。通过一些工作,你可以将它扩展到2^1000的顺序的限制(即,除了递归限制之外的其他事情,将使它无法首先工作)。

其次,不是检查每个奇数,而是检查6 mod 1和5,使用特殊情况在开始时检查2/3/5。可以使用更长距离的模式,而不仅仅是半径为6。

第三,存在足够可靠的概率素性测试,使用它们是正确的答案。您可以构建一个硬编码表,其中包含测试失败的数字,检查该表,否则进行测试,并使您的上限更高,远远高于您实际可以做的更多。

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