7

如果我在 windows 和 linux(ubuntu) 上编译以下 c 行,我会得到不同的结果。我想避免。我该怎么做?

 double a = DBL_EPSILON;
 double b = sqrt(a);
 printf("eps = %.20e\tsqrt(eps) = %.20e\n", a, b);

linux输出:

eps = 2.22044604925031308085e-16        sqrt(eps) = 1.49011611938476562500e-08

窗口输出:

eps = 2.22044604925031310000e-016       sqrt(eps) = 1.49011611938476560000e-008

在 linux 上使用 gcc 和 clang 在 32 位和 64 位系统上测试的结果相同。在 Windows 上使用 gcc-mingw 在 32 位和 visual-studio 上使用 32 位和 64 位进行测试,结果也相同。

4

1 回答 1

10

在您给出的示例中,两个程序似乎具有相同的浮点数。他们只是以不同的方式打印它们。围绕这个特定问题最简单的解决方案是编写自己的浮点打印函数。如果您不期望输出太好,您可以使用此处的函数作为伪代码来编写您自己的 C 语言。它没有正确舍入,但它适用于它的预期用途(即可重现和可读的输出)。


您的问题暗示您遇到的一个更深层次的问题是浮点计算在不同平台上给出不同的结果。这是因为 C 标准不强制编译器精确地实现 IEEE 754 浮点标准,特别是允许更高的中间结果精度。C 标准的这种相对宽松至少部分是由于历史上的 x86 浮点指令导致实现精确的 IEEE 754 语义的成本很高。

在 Linux 上,假设您使用的是 GCC,请尝试-msse2编译选项。编辑:OP评论说-msse2 -mfpmath=sse对他有用。 这使得 GCC 生成现代 SSE2 指令,提供精确的 IEEE 754 浮点语义。如果在 Windows 上您也使用 GCC,请在此处使用相同的选项。

如果您使用 Visual C:Visual C 使用另一个技巧来强制历史浮点指令匹配 IEEE 754 语义:它告诉旧的 80 位浮点硬件仅使用与 IEEE 754 双精度一样多的有效位拥有。这给出了双精度数字的准确模拟,除了一些您不会遇到的极端情况。在这种情况下,如果您的程序仅使用双精度数字(Cdouble类型),它会有所帮助(*)。

(*) Visual C 编译器理论上可以生成代码,通过将每个中间结果从双精度舍入到单精度来计算精确的单精度算术,但这会很昂贵,我怀疑它是否这样做。

于 2012-11-26T22:00:00.440 回答