【问题标题】:Is there a (Linux) g++ equivalent to the /fp:precise and /fp:fast flags used in Visual Studio?是否有 (Linux) g++ 等效于 Visual Studio 中使用的 /fp:precise 和 /fp:fast 标志?
【发布时间】:2011-03-15 03:00:22
【问题描述】:

背景:

多年前,我继承了一个代码库,该代码库使用 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' 等效项。)

更多详细信息:

我使用调用 g++ 的“make”进行编译。据我所知(make 文件有点神秘,不是我写的)添加到 g++ 调用的唯一参数是“正常”参数(包括文件夹和要编译的文件)和 -fPIC(我不确定这个开关的作用,我在“手册”页上看不到它)。

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

我尝试过发布和调试版本,VC++ 为发布和调试提供相同的结果,而 g++ 为发布和调试提供相同的结果,但我无法让 g++ 版本提供与 VC++ 相同的结果版本。

【问题讨论】:

  • 我在谷歌上搜索了一下后发现了-fPIC的含义: -fPIC 如果目标机器支持,则发出与位置无关的代码,适用于动态链接,即使(3,n)个分支需要大位移。
  • 这可能很耗时,但值得付出努力:您能否尝试找出 MSVC 和 gcc 之间某些计算存在分歧的最早指令(或至少代码行)?
  • 是的,我正在处理您的建议。不幸的是,我有点在 linux n00b 上,所以我需要一些时间才能把所有东西都放在一起!
  • 您好,您解决过这个问题吗?

标签: c++ visual-studio-2008 g++ compiler-optimization ubuntu-10.04


【解决方案1】:

来自GCC manual

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

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

稍微扩展一下,这些差异大部分来自使用 x86 80 位浮点寄存器进行计算(与用于存储 double 值的 64 位相比)。如果中间结果保存在寄存器中而不写回内存,您可以在计算中有效地获得 16 位的额外精度,使它们更精确,但可能与将中间值写入/读取到内存(或只有 64 位 FP 寄存器的架构)。

这些标志(在 GCC 和 MSVC 中)通常强制将每个中间结果截断为 64 位,从而使计算对代码生成和优化的变幻莫测以及平台差异不敏感。除了准确性/精度方面的成本之外,这种一致性通常会带来轻微的运行时成本。

【讨论】:

  • 这并不是问题所在,但感谢您深思熟虑的回复。您的链接非常有用
  • 很抱歉听到这个消息。也许它与舍入模式有关?您可能会查看生成的程序集以获得不同结果的最小程序,并查看 FPU 在 MSVC 与 GCC 中的设置是否不同。然后你可以尝试将这些 FPU 设置映射到不同的编译器标志,直到找到魔法标志。
【解决方案2】:

过度的寄存器精度仅在 FPU 寄存器上是一个问题,编译器(使用正确的启用开关)无论如何都倾向于避免这种问题。在 SSE 寄存器中进行浮点计算时,寄存器精度等于内存精度。

根据我的经验,大多数 /fp:fast 影响(和潜在的差异)来自编译器冒昧地执行代数变换。这可以像更改总和顺序一样简单:

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

可以 - 随意分配 a*(b+c) 之类的乘法,并且可以进行一些相当复杂的转换 - 所有这些都旨在重用以前的计算。 当然,在无限精度下,这种变换是良性的——但在有限精度下,它们实际上会改变结果。作为一个玩具示例,请尝试使用 a=b=2^(-23), c = 1 的 summand-order-example。MS 的 Eric Fleegal describes it in much more detail

在这方面,最接近 /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' 是默认设置的,但我确实尝试了你的建议并明确设置它,但它没有任何区别。
  • 我现在已经“接受”了这个答案,我认为它回答了我的问题,尽管不幸的是它并没有解决我的问题。 :(
  • 很抱歉听到这个消息,希望其他人有更好的主意。
【解决方案3】:

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

【讨论】:

  • 我应该使用哪个-mfpmath=sse-ffloat-store 都可以解决我的问题。
【解决方案4】:

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

这可能意味着 (a) 其中一个编译器存在编译器错误,或者更可能是 (b) 数学库错误。我会深入研究您计算中的各个函数,并缩小差异所在。届时您可能会找到解决方法,如果您确实发现了错误,我相信相关团队会很乐意听到。

【讨论】:

  • 谢谢德鲁,我认为你是对的,我会按照你的建议去做
【解决方案5】:

-mpc32 还是-mpc64?

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 2013-05-06
    • 2011-07-02
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多