我有一些非平凡的C ++ 17函数标记为constexpr
。他们正在进行图形相关的计算(深度优先遍历)和通用算法(例如,查找,排序,唯一...)。
如果我尝试通过将结果放入constexpr
全局变量来强制在编译时求值,则会发生3种情况:
如果我删除constexpr
限定词并要求运行时计算,则编译和执行非常快(少于5秒)
我将g ++ 8.2与-O3 -std = c ++ 17一起使用。
为什么要花这么长时间? g ++是否因constexpr
的编译时优化问题而闻名?
在编译期间,我对constexpr
函数有什么期望?据我了解,编译器将自己转换为constexpr
计算的解释器。但是我绝对没有疑问,鉴于数据量非常小,用Python评估同一程序将非常快。
编辑:here(GCC开发人员的博客)中提到了此类问题
答案 0 :(得分:2)
g ++记住编译时间结构。此外,编译时结构可能会沿着都要创建和检查的分支(而不是不需要的分支)创建和检查,除非您非常小心。
指数爆炸很可能发生,也许就是您所看到的。
有一些减少编译时间复杂度的策略。避免深度递归。注意累积的符号长度。确保只需要检查要分支的分支。
我的意思是,检查一个非常简单的东西:
std::conditional_t< (A<B), make_type_A<Ts...>, make_type_B<Ts...> >
此代码的编写者可能只打算创建一种类型,但是此代码要求创建两种类型。
这不太可能是您的问题,但是在运行constexpr
代码时可能会发生类似的问题。
对于每个呼叫,计算所需状态的大小。总计所需的总状态。产生10倍的开销。
您还可以通过完成两个以上的样本来分析问题的O表示。查看100、200、300、400、500尺寸图。尝试使用线性图,平凡图,完整图,具有恒定或百分比连通性的随机图。
编译时间增长的O标记可以帮助您缩小问题所在的范围。如果它是线性,多项式或指数式的,您将要研究各种问题。
线性和急剧的弯曲意味着您遇到了资源瓶颈。也许是记忆。开始绘制其他资源使用情况的图表,看看是否可以找到瓶颈。
如果不记录图形并放大“悬崖”,则指数看上去很像带有悬崖的线性。可能有一个狭窄的部分,其中指数部分留下了常数因子。
多项式变得有趣。多项式的顺序(对数图可以帮助您找到答案)可以告诉您哪种操作使您费力。就像知道您的常规算法是O(n ^ 3)一样,这意味着您正在寻找三重循环。 O(n ^ 3)的编译时间意味着您正在以某种方式实例化等效于三重循环。