GCC是否会为运行时保留固定值的算术或编译输出?

Erk*_*ing 5 c c++ math optimization gcc

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

const float halfPi = M_PI/2;
Run Code Online (Sandbox Code Playgroud)

它会"归结"这个等式并设定

const float halfPi = 1.57079;
Run Code Online (Sandbox Code Playgroud)

或者算术运行时间?

Mat*_* M. 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
Run Code Online (Sandbox Code Playgroud)

令人惊讶......对吗?如果编译是在运行时完成的,那么结果可能会有所不同,具体取决于是否使用了寄存器(具有更大的位宽).

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

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


BoB*_*ish 5

今天是你的幸运日,因为你了解了Agner Fog及其惊人的深度c++手册!如果你看一下这个部分8.2,你会发现基本上所有的编译器都能够不断折叠.

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