Optimization 浮点代码与GCC的一致性

Optimization 浮点代码与GCC的一致性,optimization,gcc,floating-point,Optimization,Gcc,Floating Point,我做一些数值计算,在使用GCC时,我经常遇到浮点计算的问题。就我目前的目的而言,我不太在乎结果的真实精度,但我想要这一固定资产: 无论我的程序中的代码在哪里,当它在相同的输入上运行时,我希望它给出相同的输出 我如何强制GCC这样做?具体来说,快速数学和不同的O优化的行为是什么 我听说GCC可能会尝试变得更聪明,有时在寄存器中加载浮点数,有时直接从内存中读取浮点数,这可能会改变浮点数的精度,从而产生不同的输出。我怎样才能避免这种情况 同样,我想: 我的计算速度很快 我的计算是可靠的(即相同的输入

我做一些数值计算,在使用GCC时,我经常遇到浮点计算的问题。就我目前的目的而言,我不太在乎结果的真实精度,但我想要这一固定资产:

无论我的程序中的代码在哪里,当它在相同的输入上运行时,我希望它给出相同的输出

我如何强制GCC这样做?具体来说,快速数学和不同的O优化的行为是什么

我听说GCC可能会尝试变得更聪明,有时在寄存器中加载浮点数,有时直接从内存中读取浮点数,这可能会改变浮点数的精度,从而产生不同的输出。我怎样才能避免这种情况

同样,我想:

  • 我的计算速度很快
  • 我的计算是可靠的(即相同的输入->相同的结果)
  • 我不太关心这个特定代码的精度,所以如果这带来了可靠性,我可以降低精度

有谁能告诉我解决这个问题的方法吗?

如果您的目标包括x86处理器,使用使gcc使用SSE2指令(而不是基于历史堆栈的指令)的开关将使这些指令的运行更像其他指令

如果您的目标包括PowerPC处理器,则使用开关使gcc使用
fmadd
指令(替换源代码中的乘法和加法)将使这些处理器的运行更像其他处理器

不要使用
--fast math
:这允许编译器采用一些快捷方式,这将导致架构之间的差异。Gcc更符合标准,因此在没有此选项的情况下是可预测的

在应用程序中包含您自己的数学函数(
exp
sin
,…),而不是依赖系统库中的函数,这只能帮助提高可预测性


最后,即使编译器严格遵守标准(这里我指的是C99),也可能存在一些差异,因为C99允许以比表达式类型更高的精度计算中间结果。如果您真的希望程序总是给出相同的结果,请编写。或者,仅使用所有计算可用的最大精度,如果可以避免使用历史x86指令,则该精度将为
double
。无论如何,不要为了提高可预测性而使用精度较低的浮动:根据标准中的上述条款,效果会相反。

我认为GCC已经有了很好的文档记录,所以我不会试图回答您关于其选项及其影响的部分问题,从而暴露我自己的无知。不过,我想概括地说,当涉及数字精度和性能时,阅读手册会带来很大的好处。从事GCC工作的聪明人在他们的文档中投入了大量精力,阅读它是值得的(好吧,它可能有点枯燥,但见鬼,它是一本编译器手册,而不是紧身衣裂土器)

如果得到与最后一位数字结果相同的结果对您来说很重要,那么您需要关注的不仅仅是GCC以及如何控制其行为。您需要锁定它调用的库、它运行的硬件,以及我尚未想到的一些其他因素。在最坏的情况下,你甚至可能想要,我已经看到了,编写你自己的f-p数学实现来保证跨平台的位身份。这是很困难的,因此成本很高,并且可能会让您对自己代码的正确性比GCC代码的正确性更不确定

然而,你写

我不太关心这个特定代码的精度,所以如果这带来了可靠性,我可以降低精度

这就向你提出了一个问题——你为什么不简单地使用5位小数作为你的(减少的)精度标准?这是我们很多数值计算领域的人一直在做的事情;我们忽略了数值分析的更精细的方面,因为它们很难避免,并且计算时间昂贵。我在想区间算术和高精度数学。(当然,如果5不适合您,请选择另一个单位数字。)

但好消息是,这是完全有道理的:我们处理的科学数据本质上是带有错误的(当然,我们通常不知道错误是什么,但那是另一回事),所以可以忽略十进制表示的最后几个数字,比如说64位f-p数。继续,忽略其中的几个。更妙的是,不管你的f-p数有多少位,在计算机上进行数值计算总是会失去一些精度;增加更多的位只会将错误向后推,既朝着最低有效位,又朝着长时间运行的计算结束的方向

您必须注意的情况是,您的算法太差,或者算法的实现太差,以至于很快就会失去很多精度。这通常表现为f-p数的任何合理大小。如果这对您来说是一个真正的问题,那么您的测试套件应该已经暴露了这一点


总而言之:您必须以某种方式处理精度损失,在地毯下刷更精细的细节并不一定是错误的。

此外,困扰您的正是那些试图为C编写正确分析器的人,因此您应该对此报告感兴趣:。除了分析器作者没有对编译选项的控制,但是他们在一个框架中工作,在这个框架中,它足以考虑所有的可能性,而不会忘记任何可能性。