【问题标题】:Different math rounding behaviour between Linux, Mac OS X and WindowsLinux、Mac OS X 和 Windows 之间的不同数学舍入行为
【发布时间】:2009-12-25 16:26:54
【问题描述】:

嗨,

我开发了一些混合 C/C++ 代码,并进行了一些密集的数值计算。在 Linux 和 Mac OS X 中编译时,模拟结束后我得到非常相似的结果。在 Windows 中,该程序也可以编译,但我得到的结果非常不同,有时该程序似乎无法运行。

我在所有系统中都使用了 GNU 编译器。有朋友推荐我加了-frounding-math,现在windows版本好像更稳定了,但是Linux和Os X,他们的结果一点都没有改变。

您能否推荐其他选项以在 Win 和 Linux/OSX 版本之间获得更多一致性?

谢谢

P.D.我还尝试了 -O0 (没有优化)并指定了 -m32

【问题讨论】:

  • Linux 和 OS X 都使用 GCC,所以我希望得到完全相同的结果——前提是它们都运行在相同的处理器架构上。你真的在那里得到了“相似”的结果吗?如果是这样,一些随机性似乎会注入到您的计算中。任何未初始化的变量?!

标签: c++ c math


【解决方案1】:

我无法谈论在 Windows 中的实现,但英特尔芯片包含 80 位浮点寄存器,并且可以提供比 IEEE-754 浮点标准中指定的更高的精度。您可以尝试在应用程序的 main() 中调用此例程(在 Intel 芯片平台上):

inline void fpu_round_to_IEEE_double()
{
   unsigned short cw = 0;
   _FPU_GETCW(cw);        // Get the FPU control word
   cw &= ~_FPU_EXTENDED;  // mask out '80-bit' register precision
   cw |= _FPU_DOUBLE;     // Mask in '64-bit' register precision
   _FPU_SETCW(cw);        // Set the FPU control word
}

认为这与@Alok 讨论的舍入模式不同。

【讨论】:

  • +1 用于提及 80 位寄存器。我不知道_FPU_*
  • 那是在 x87 上,不应该再使用了。 SSE 数学要快得多
【解决方案2】:

浮点数有四种不同类型的舍入:向零舍入、向上舍入、向下舍入和舍入到最接近的数字。根据编译器/操作系统,默认值可能在不同系统上有所不同。有关以编程方式更改舍入方法,请参阅fesetround。它由 C99 标准指定,但可能对您可用。

您也可以尝试-ffloat-store gcc 选项。这将试图阻止 gcc 在寄存器中使用 80 位浮点值。

此外,如果您的结果因舍入方法而异,并且差异很大,则意味着您的计算可能不稳定。请考虑进行区间分析,或使用其他方法来查找问题。有关详细信息,请参阅 How Futile are Mindless Assessments of Roundoff in Floating-Point Computation? (pdf) 和 The pitfalls of verifying floating-point computations(ACM 链接,但如果这不适合您,您可以从很多地方获取 PDF)。

【讨论】:

  • +1 用于数值稳定性:如果结果因四舍五入而有很大差异,则计算有问题。并且只是为了排除明显的问题:您确实使用了“双”,而不仅仅是“浮动”作为变量?!
【解决方案3】:

除了人们提到的运行时舍入设置之外,您还可以在“属性”>“C++”>“代码生成”>“浮点模型”中控制 Visual Studio 编译器设置。我已经看到将其设置为“Fast”的情况可能会导致一些不良的数值行为(例如迭代方法无法收敛)。

这里解释了这些设置: http://msdn.microsoft.com/en-us/library/e7s85ffb%28VS.80%29.aspx

【讨论】:

  • 这会遇到同样的问题。可以设置 VC++ 浮点模型设置以强制 80 位内部表示在明确定义的时间四舍五入到它们的 64 位等价物,这应该使结果与一直使用 64 位的其他实现一致通过。
【解决方案4】:

IEEE 和 C/C++ 标准未指定浮点数学的某些方面。是的,添加到浮点数的精确结果是确定的,但任何更复杂的计算都不是。例如,如果您添加三个浮点数,那么编译器可以以浮点精度、双精度或更高精度进行计算。同样,如果您添加三个双精度,那么编译器可能会以双精度或更高精度进行计算。

VC++ 默认将 x87 FPU 的精度设置为双倍。我相信 gcc 会保持 80 位精度。显然两者都不是更好,但是它们很容易给出不同的结果,尤其是在您的计算存在任何不稳定性的情况下。特别是如果您有额外的精度(或者如果评估顺序发生变化),“小 + 大 - 大”可能会给出非常不同的结果。此处讨论了不同中间精度的含义:

http://randomascii.wordpress.com/2012/03/21/intermediate-floating-point-precision/

此处讨论确定性浮点的挑战:

http://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

浮点数学很棘手。您需要找出您的计算何时出现偏差并检查生成的代码以了解原因。只有这样你才能决定采取什么行动。

【讨论】:

    猜你喜欢
    • 2012-11-25
    • 2015-09-15
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 2012-09-16
    • 2017-12-14
    • 1970-01-01
    相关资源
    最近更新 更多