现代硬件算法[4.5]: 预计算
预计算
当编译器可以推断某个变量不依赖于任何用户提供的数据时,他们可以在编译时计算其值,并将其嵌入生成的机器代码,转化为常量。
这种优化对性能有很大帮助,但它不是C++标准的一部分,所以编译器不必这么做。当编译时计算很难实现或时间密集时,编译器可能会错过这个机会。
常量表达式
一个更可靠的解决方案,在现代C++中,可以将函数标记为constexpr
;如果它是通过传递常量来调用的,则其值保证在编译时计算:
constexpr int fibonacci(int n) { |
这些函数有一些限制,比如它们只能调用其他constexpr
函数,不能进行内存分配,但除此之外,它们还是会“按原样”执行。
请注意,虽然constexpr
函数在运行时不会花费任何费用,但它们仍然会增加编译时间,因此至少还是要关心一下它们的效率,不要在其中放入非确定性多项式完全问题(NP-Complete,NPC)的东西:
constexpr int fibonacci(int n) { |
在早期的C++标准中,曾经有更多的限制,比如你不能在其中使用任何声明,必须依赖递归,所以整个过程感觉更像是Haskell编程(一种函数式编程语言),而不是C++。自从C++17以来,你甚至可以使用强制方式计算静态数组,这对于预计算查找表非常有用:
struct Precalc { |
请注意,当你在调用constexpr
函数时传递非常量,编译器在编译时可能会也可能不会计算它们:
for (int i = 0; i < 100; i++) |
在这个例子中,尽管我们执行恒定次数的迭代,并使用编译时已知的参数调用fibonacci
,但从技术上来说,它们不是编译时常数。是否优化这个循环取决于编译器——对于繁重的计算,编译器通常选择不优化。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 旭穹の陋室!
评论