如何确保不同系统上的浮点数相同?

Wil*_*ill 7 c floating-point platform-independent

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

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

linux输出:

eps = 2.22044604925031308085e-16        sqrt(eps) = 1.49011611938476562500e-08
Run Code Online (Sandbox Code Playgroud)

窗口输出:

eps = 2.22044604925031310000e-016       sqrt(eps) = 1.49011611938476560000e-008
Run Code Online (Sandbox Code Playgroud)

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

Pas*_*uoq 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双精度一样多的有效位数具有.这样可以精确模拟双精度数字,除了一些你不会遇到的极端情况.在这种情况下,如果您的程序仅使用双精度数字(C double类型),它将有助于(*).

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