在编译时计算小整数的阶乘

时间:2012-07-31 17:57:43

标签: c++ math boost template-meta-programming constexpr

我刚刚(再次)实现了一个递归模板,用于在编译时计算整数的阶乘(谁曾想过有一天我真的需要它!)。尽管如此,我还是去Boost寻找答案,而不是自己动手。但是,特殊数学中的阶乘函数特别禁止它使用整数类型,所以我只写了自己的。

仍然,我应该使用Boost中的另一个功能吗?我应该将整数转换为double并使用boost::factorial函数吗?计算是在编译时执行的吗?

2 个答案:

答案 0 :(得分:9)

你不需要Boost,如果你有C ++ 11,这只是1-liner:

constexpr uint64_t factorial(uint64_t n) { 
    return n == 0 ? 1  :  n * factorial(n-1); 
}

即使你的arg也不是编译时间常量,它也会工作。 uint64_t将与n< 21.

如果您在编译时执行此操作并乘以浮点值 - 则不会产生转换开销(转换也将在编译时进行)。

答案 1 :(得分:3)

由于可以在整数内部使用有限数量的阶乘,因此您可以手动预先计算前20个值并将它们存储在全局或静态数组中。然后使用全局或静态函数来查找数组中的阶乘:

#include <iostream>

const int factorials[] =
{
    1,
    1,
    2,
    6,
    24,
    // etc...
};

inline const int factorial(int n) {return factorials[n];}

int main()
{
    static const int fourFactorial = factorial(4);
    std::cout << "4! = " << fourFactorial << "\n";
}

如果使用文字作为factorial的参数,则编译器应该简单地用函数调用替换结果(启用优化时)。我在XCode 4.4中尝试了上面的例子(在Mac上),我在程序集中看到它用常量24初始化fourFactorial

.loc    1 20 38  ## /Users/emile/Dev/sandbox/sandbox/main.cpp:20:38
movl    $24, __ZZ4mainE13fourFactorial(%rip)

与使用递归编译时技巧相比,此方法可能导致更快的编译。