我知道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
一起使用(如果没有,为什么不这样做)?
答案 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>