我想知道 GCC 是否会将具有固定值的算术保留在运行时执行,或者是否会将其设置为它的答案,例如。
const float halfPi = M_PI/2;
它会“简化”方程式并设置
const float halfPi = 1.57079;
还是将算法留给运行时?
我想知道 GCC 是否会将具有固定值的算术保留在运行时执行,或者是否会将其设置为它的答案,例如。
const float halfPi = M_PI/2;
它会“简化”方程式并设置
const float halfPi = 1.57079;
还是将算法留给运行时?
好吧......如果我们谈论积分,答案将是明确的“是”(在通用术语下恒定折叠)。即使是冗长的计算也可以在编译时完成......这实际上是模板非类型参数评估和(现在)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
(真的不知道)控制。因为即使编译器肯定可以做到,你可能会告诉它不要(在不知不觉中)。
因此,唯一可靠的测试方法是检查编译器输出;通过检查目标代码或通过要求编译器发出程序集。您将需要检查您使用的每个选项组合的此输出。