【问题标题】:What's the most efficient tail recursive prime verification function known?已知最有效的尾递归素数验证函数是什么?
【发布时间】:2013-06-03 01:31:43
【问题描述】:

到目前为止,我一直在尝试元编程:

// 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 函数。

【问题讨论】:

  • 其实不是那个的复制品——这个是关于尾递归的。

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


【解决方案1】:

是的。

首先,您的主要限制之一是您的递归深度限制。对于从3sqrt(N) 的每个奇数,您的递归一次。递归限制约为 1000 次,这意味着您最多只能处理 100 万个数字。您需要减少正在执行的递归量。

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

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

第三,有足够可靠的概率素性检验,使用它们是正确的答案。您可能可以建立一个测试失败的数字的硬编码表,对照该表进行检查,然后进行测试,并使您的上限远远高于您实际上可以做到的。

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

【讨论】:

  • 对于我感兴趣的尾递归用例,递归限制是否适用?因为目标代码不包含递归,只有源代码。虽然我提供了一个元编程示例,但编译时并不是我唯一的兴趣,因此我强调尾递归。
  • @chico 好点。我不知道尾递归标准中有一个例外,尽管也许应该有。
  • @chico 由于我错过了尾递归在您的问题中的重要性,您是否希望我删除此答案以使您的问题仍未得到解答?
  • 但是,如果“可能重复”和“投票赞成”被删除,我会很高兴,因为提到的重复目标没有提到任何尾递归提示和约束。
  • @chico 我不能“取消投票关闭”,但如果它打破 5,我可以“投票重新开放”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-10
  • 2019-09-14
  • 2018-09-02
相关资源
最近更新 更多