浮点优化 – 指南
我们需要通过在C / C ++中实现特定算法来解决的大多数科学计算问题要求精度远低于双精度。 例如, 1e-6
1e-7
精度覆盖了99%
的ODE求解器或数值积分的情况。 即使在我们确实需要更高精度的极少数情况下,通常数值方法本身也会失败,然后才能达到接近双精度的精度。 示例:即使在因舍入误差而求解标准nostiff常微分方程时,我们也不能期望从简单的Runge-Kutta方法获得1e-16精度。 在这种情况下,双精度要求类似于要求更好地逼近错误答案。
然后,在大多数情况下,积极的浮点优化似乎是一个双赢的局面,因为它使您的代码更快(更快!)并且它不会影响您的特定问题的目标准确性。 也就是说,确保特定的实现/代码对fp优化是稳定的似乎非常困难。 古典(有点令人不安)的例子:GNL,GNU科学图书馆,不仅是市场上的标准数字图书馆,而且它是一个写得很好的图书馆(我无法想象自己做得更好)。 但是,GSL对fp优化不稳定。 实际上,例如,如果使用intel编译器编译GSL,那么除非打开-fp-model strict
标志关闭fp优化,否则它的内部测试将失败。
因此,我的问题是:是否存在编写代码的一般准则,这些准则对于积极的浮点优化是稳定的。 这些指南语言(编译器)是否具体。 如果是这样,那么C / C ++(gcc / icc)的最佳实践是什么?
注1:这个问题不是询问gcc / icc中的fp优化标志是什么。
注2:这个问题并不是要求关于C / C ++优化的一般指导原则(比如不要对很多小型函数使用虚函数)。
注3:这个问题并不是要求大多数标准fp优化列表(比如x / x – > 1)。
注4:我坚信这不是类似于传统的“最酷的服务器名称”的主观/偏离主题的问题。 如果您不同意(因为我没有提供具体示例/代码/问题),请将其标记为社区维基。 我对答案比对获得一些状态点更感兴趣(不是它们不重要 – 你明白了!)。
编译器制造商通过断言这些优化对数值稳定算法的影响很小,certificate了-ffast-math
类型的优化。
因此,如果要编写对这些优化具有鲁棒性的代码,则充分条件是只编写数值稳定的代码。
现在你的问题可能是,“我如何编写数值稳定的代码?”。 这是你的问题可能有点广泛的地方:有完整的书籍专门讨论这个主题。 我已经链接到的维基百科页面有一个很好的例子, 这是另一个好的例子。 我不能特别推荐一本书,这不是我的专业领域。
注1:数值稳定性的可取性超出了编译器优化。 如果您有选择,即使您不打算使用-ffast-math
style优化,也要编写数值稳定的代码。 即使使用严格的IEEE 754浮点语义进行编译,数值不稳定的代码也可能提供错误的结果。
注意2:使用-ffast-math
style标志编译时,不能指望外部库可以工作。 这些由浮点专家编写的库可能需要使用IEEE 754计算的属性进行微妙的技巧。 这种技巧可以通过-ffast-math
优化来打破,但是它们可以比你期望编译器提高性能,即使你让它。 对于浮点计算,具有领域知识的专家每次都会击败编译器。 许多例子中有CRlibm中的三重双重实现。 如果未使用严格的IEEE 754语义编译,则此代码会中断。 编译器优化中断的另一个更基本的算法是Kahan求和 :当使用不安全优化编译时, c = (t - sum) - y
被优化为c = 0
。 当然,这完全违背了算法的目的。