5

我想知道 GCC 是否会将具有固定值的算术保留在运行时执行,或者是否会将其设置为它的答案,例如。

const float halfPi = M_PI/2;

它会“简化”方程式并设置

const float halfPi = 1.57079;

还是将算法留给运行时?

4

2 回答 2

8

好吧......如果我们谈论积分,答案将是明确的“”(在通用术语下恒定折叠)。即使是冗长的计算也可以在编译时完成......这实际上是模板非类型参数评估和(现在)constexpr变量所必需的。

浮点表示的情况下,一旦计算变得更复杂,事情就会变得有点复杂。问题是不同大小(以及精度)的浮点表示对于相同的基本输入会产生不同的结果。

要理解为什么,假设它float最多具有 5 位精度:

   5.0000 + 0.00001
-> 5.00001
-> 5.0000 (truncation to 5 digits)

   5.0000 + 0.00001 + ... + 0.00001 (10 times)
-> 5.0000 + 0.00001 + ... + 0.00001 (9 times)
-> 5.0000 + 0.00001 + ... + 0.00001 (8 times)
-> ...
-> 5.0000

令人惊讶……对吧?如果编译是在运行时完成的,那么结果可能会根据是否使用寄存器(具有更大位宽)而有所不同。

因此,是否发生常量折叠可能取决于您使用的优化标志集。例如,对于 gcc,这可能由-freciprocal-math(真的不知道)控制。因为即使编译器肯定可以做到,你可能会告诉它不要(在不知不觉中)。

因此,唯一可靠的测试方法是检查编译器输出;通过检查目标代码或通过要求编译器发出程序集。您将需要检查您使用的每个选项组合的此输出。

于 2013-04-02T11:46:01.060 回答
5

今天是你的幸运日,因为你会发现 Agner Fog 和他令人惊叹的深度c++手册!如果你看一下这个8.2部分,你会发现基本上所有的编译器都能够进行常量折叠。

尽管使用编译器选项确保它确实发生在这种特殊情况下,但您应该按照上面的建议检查程序集输出(使用-S)。我喜欢asm("MY_LABEL:");在代码中放置类似附近的内容以便于查找,但请记住,这可能会改变代码的含义,从而改变编译器解释它的方式。在这种情况下,我不相信它会改变任何东西。

于 2013-04-02T11:15:36.857 回答