C ++:尝试通过组合和Pascal三角形了解constexpr

时间:2018-08-03 23:35:36

标签: c++ templates c++14 combinations constexpr

我知道constexpr应该可以消除/简化过去使用的许多模板编程技巧,但是对于C ++ 11来说我还是一个新手,我很难理解为什么,在计算组合函数时:

C(n,r) = n!/(r!(n-r)!) = C(n-1,r-1) + C(n-1,r)

递归方法在预期的运行时执行速度很慢,但是它允许对较大值使用C(n,r)进行计算,但对于模板来说效果很好,但是我无法使其与{{ 1}}。这是我正在使用的模板代码:

constexpr

这是using factorial_t = unsigned long long; template<size_t N, size_t R> struct recursive_combinations { enum: factorial_t { value = recursive_combinations<N-1, R>::value + recursive_combinations<N-1, R-1>::value}; }; template<size_t N> struct recursive_combinations<N,0> { enum: factorial_t { value = 1 }; }; template<size_t N> struct recursive_combinations<N,N> { enum: factorial_t { value = 1 }; }; 版本(也许我在这里做错了):

constexpr

当我尝试这样做时:

constexpr const factorial_t recursiveCombinations(const size_t N, const size_t R) {
    if (R == N || R == 0) return 1;
    return recursiveCombinations(N-1, R) + recursiveCombinations(N-1, R-1);
}

一切都很好,我得到了47,129,212,243,960的预期结果,这是无法通过计算阶乘获得的。

但是,当我尝试此操作时:

constexpr auto comb1_50_30 = recursive_combinations<50,30>::value;

编译器(clang v5.0.1,设置为C ++ 17模式)抱怨constexpr auto comb2_50_30 = recursiveCombinations(50, 30); 必须由常量表达式初始化。

有人可以帮我弄清楚我做错了什么吗,或者是否有办法使它与comb2_50_30一起使用(如果没有,为什么不这样做)?

2 个答案:

答案 0 :(得分:3)

  

抱怨comb2_50_30必须用一个常量表达式初始化。

错误的下一行告诉您原因:

note: constexpr evaluation hit maximum step limit; possible infinite loop?

您的扩展对于constexpr评估来说,在计算上简直太昂贵了。您可以使用-fconstexpr-steps=X-fconstexpr-depth=X来增加允许编译器计算constexpr函数的工作量,但是我没有设法找到允许您的{{1} }在clang上进行编译。

g ++可以很好地编译recursiveCombinations(50, 30)版本。

答案 1 :(得分:3)

以将结果的限制减少min(r, n-r)的一个因素为代价,可以使用以下效率更高的实现:

constexpr uint64_t efficientCombinations(uint64_t n, uint64_t r)
{
    uint64_t accum = 1U;
    if (n - r > r) r = n - r;
    for( uint64_t x = 1; x <= n - r; ++x )
    {
        accum *= (r + x);
        accum /= x;
    }
    return accum;
}

为了与C ++ 11兼容,如果有些混乱,将迭代转换为递归很简单。

(注意:根据“使正常工作”的意思,根据这种方法更改算法可能不是理想的方法……但是太大了,无法发表评论)< / p>