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

Computing the factorial of a small integer at compile time

本文关键字:整数 阶乘 计算 编译      更新时间:2023-10-16

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

不过,Boost中还有其他我应该使用的函数吗?我应该将整数强制转换为double并使用boost::factorial函数吗?计算是否在编译时执行?

你不需要Boost,如果你有C++11:,这只是一行

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

即使arg不是编译时常数,它也能工作。uint64_t将与n<21.

如果您在编译时执行此操作并与浮点值相乘,则不会有转换开销(转换也将在编译时进行)。

由于整数中可以容纳的阶乘数量有限,因此您可以手动预计算前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)

这种方法可能会比使用递归编译时技巧更快地进行编译。