是否有Linux下的g++等价于Visual Studio中使用的/fp:precise和/fp:fast标志?

11

背景:

很多年前,我继承了一个代码库,其中某个计算密集型的库使用Visual Studio(VC++)标志'/fp:fast'来生成更快的代码。不幸的是,'/fp:fast'生成的结果与另一个编译器(Borland C++)下相同库的结果略有不同。由于我们需要产生完全相同的结果,因此我切换到了'/fp:precise',这是可以正常工作的,自那以后一切都非常顺利。但是,现在我正在使用uBuntu Linux 10.04上的g ++编译相同的库,我看到类似的行为,并且我想知道它是否可能有类似的根本原因。我的g ++构建的数字结果与我的VC ++构建的数字结果略有不同。这就带来了我的问题:

问题:

g ++是否具有等效或类似于VC ++中‘fp:fast’和‘fp:precise’选项的参数?(它们是什么?我想激活等效的‘fp:precise’选项。)

更详细的信息:

我使用'make'进行编译,它调用g ++。据我所知(make文件有点晦涩,而且不是我编写的),唯一添加到g ++调用中的参数是“常规”参数(包括文件夹和编译的文件)以及-fPIC(我不确定此开关的作用,我在'man'页面上看不到它)。

‘man g++’中唯一相关的参数似乎是打开优化选项的参数。(例如-funsafe-math-optimizations)。但是,我认为我没有打开任何东西,我只想关闭相关的优化。

我尝试了发布和调试版本,VC++的发布版本和调试版本给出相同的结果,而g ++的发布版本和调试版本也给出相同的结果,但是我无法让g ++版本给出与VC ++版本相同的结果。


通过更多的谷歌搜索,我找到了-fPIC的含义: -fPIC:如果目标机器支持,生成适用于动态链接的位置无关代码,即使(3,n)分支需要大位移。 - Boinst
这可能会耗费一些时间,但绝对值得努力:您能否尝试确定MSVC和gcc之间某些计算发散的最早指令(或至少是代码行)? - Ofek Shilon
是的,我正在按照您的建议进行工作。不幸的是,我对Linux还不太熟悉,所以需要一些时间来整理好一切! - Boinst
你好,你曾经解决过这个问题吗? - Pythagoras of Samos
5个回答

18

来自GCC手册:

-ffloat-store 不要将浮点变量存储在寄存器中,并禁止其他可能改变浮点值是从寄存器还是从内存中取出的选项。

此选项可防止在诸如68000等机器上出现不必要的过度精度,其中浮点寄存器(68881)保留的精度比double应有的精度更高。x86架构也是如此。对于大多数程序,过度精度只会带来好处,但一些程序依赖于IEEE浮点的精确定义。对于此类程序,可以使用-ffloat-store,在将所有相关计算存储到变量中后使用。

稍作扩展,这些差异大部分来自于在计算中使用x86 80位浮点寄存器(vs.用于存储double值的64位)。如果中间结果保持在寄存器中而不写回到内存中,那么您的计算实际上获得了16位额外的精度,使其更精确,但可能与写入/读取中间值到内存或在仅具有64位FP寄存器的架构上进行的计算所生成的结果不一致。

这些标志(在GCC和MSVC中都适用)通常强制将每个中间结果截断为64位,从而使得计算对代码生成、优化和平台差异不敏感。这种一致性通常伴随着轻微的运行时成本以及精度/准确性方面的成本。


这并不是问题的原因,但感谢您深思熟虑的回复。您提供的链接非常有用。 - Boinst
很抱歉听到这个。也许与舍入模式有关?您可以查看生成的汇编代码,针对一个最小化程序,看看在 MSVC 和 GCC 中是否设置了不同的 FPU。然后,您可以尝试将这些 FPU 设置映射到不同的编译器标志,直到找到魔法标志。 - Drew Hall

10

超出寄存器精度的问题只存在于FPU寄存器上,而编译器(在启用正确的开关时)往往会避免使用它们。当浮点运算在SSE寄存器中进行时,寄存器精度等于内存精度。

根据我的经验,/fp:fast对代码的影响(和潜在差异)大多来自编译器对代数变换进行的部分推导,这可能仅仅是改变加和顺序:

( a + b ) + c --> a + ( b + c)

可以随意分配乘法,比如a*(b+c),并且可以进行一些相当复杂的变换,旨在重用先前的计算结果。当然,在无限精度下,这些变换是良性的,但在有限精度下,它们实际上会改变结果。作为一个玩具示例,尝试使用a=b=2^(-23)和c=1来进行加和顺序示例。微软的Eric Fleegal在此处更详细地描述了这个问题。

在这方面,最接近/fp:precise的gcc开关是-fno-unsafe-math-optimizations。我认为它默认打开,你可以尝试显式设置它并查看是否有差异。同样,你可以尝试显式关闭所有-ffast-math优化:-fno-finite-math-only,-fmath-errno,-ftrapping-math,-frounding-math和-fsignaling-nans(最后两个选项是非默认的!)


谢谢你的建议!'no-unsafe-math-optimizations'默认已经设置了,但我尝试了你建议的显式设置,但没有任何改变。 - Boinst
我现在“接受”了这个答案,我认为它回答了我的问题,尽管对我来说不幸的是它没有解决我的问题。 :( - Boinst
很遗憾听到这个消息,希望其他人可能会有更好的想法。 - Ofek Shilon

5

我认为没有确切的等价物。你可以尝试使用-mfpmath=sse代替默认的-mfpmath=387,看看是否有帮助。


我应该使用-mfpmath=sse还是-ffloat-store?两者都可以解决我的问题。 - EmptyData

1

这绝对与优化标志无关,假设您所说的“Debug”是指“关闭优化”。如果g++在调试和发布版本中给出相同的结果,则意味着这不是与优化相关的问题。调试构建应始终将每个中间结果存储在内存中,从而保证与MSVC的/fp:precise相同的结果。

这很可能意味着(a)编译器中存在错误之一,或更可能的是(b)数学库中存在错误。我会逐个函数地深入计算,并缩小差异所在的范围。此时,您可能会找到解决方法,如果发现错误,我相信相关团队会很乐意听取反馈。


谢谢Drew,我认为你是对的,我会按照你的建议去做。 - Boinst

0

-mpc32 还是 -mpc64?

但是您可能需要重新编译带有开关的 C 和数学库以查看差异... 这也适用于其他建议的选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接