Linux,Mac OS X和Windows之间的不同数学舍入行为

HI,

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

我在所有系统中都使用了GNU编译器。 有些朋友建议我添加-frounding-math,现在windows版本似乎工作更稳定,但Linux和Os X,他们的结果,根本不会改变。

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

谢谢

PD我也试过-O0(没有优化)并指定-m32

我无法谈论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讨论的舍入模式不同。

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

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

此外,如果您的结果根据舍入方法而变化,并且差异很大,则意味着您的计算可能不稳定。 请考虑进行区间分析,或使用其他方法来查找问题。 有关更多信息,请参阅浮点计算中无效无效评估的无效评估? (pdf)和validation浮点计算的缺陷 (ACM链接,但如果这对你不起作用,你可以从许多地方获得PDF)。

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

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

IEEE和C / C ++标准未指定浮点数学的某些方面。 是的,确定添加到浮点数的确切结果,但更复杂的计算不是。 例如,如果添加三个浮点数,则编译器可以以float精度,双精度或更高精度执行求值。 同样,如果添加三个双精度数,则编译器可以以双精度或更高精度进行求值。

VC ++默认将x87 FPU精度设置为double。 我相信gcc会以80位的精度离开它。 两者都没有明显更好,但它们可以很容易地给出不同的结果,特别是如果计算中存在任何不稳定性。 特别是“微小+大 – 大”可能会产生非常不同的结果,如果你有额外的精度(或评估的顺序改变)。 这里讨论了不同中间精度的含义:

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

这里讨论确定性浮点的挑战:

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

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