如果我在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
windows输出:
eps = 2.22044604925031310000e-016 sqrt(eps) = 1.49011611938476560000e-008
在linux上测试了gcc和clang在32位和64位系统上的相同结果。 在使用32位的gcc-mingw和32位和64位的visual-studio测试的Windows上,也有相同的结果。
答案 0 :(得分:9)
在您给出的示例中,似乎两个程序都具有相同的浮点数。他们只是打印不同的方式。围绕这个特定问题的最简单的解决方案是编写自己的浮点打印功能。如果你没有期望太好的输出,你可以使用函数here作为伪代码在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一样多的有效位数双精度有。这样可以精确模拟双精度数字,除了一些你不会遇到的极端情况。在这种情况下,如果您的程序仅使用双精度数字(C double
类型),它将有助于(*)。
(*)Visual C编译器理论上可以通过将每个中间结果从双精度舍入到单精度来生成计算精确单精度算术的代码,但这样做会很昂贵,我怀疑它是否会这样做。