Windows 和 Linux 上 Fortran 中 LOG10 的不同结果
Different results for LOG10 in Fortran on Windows and Linux
我一直在研究需要在 Windows 和 Linux 上 运行 的混合 C++/Fortran 数字代码,并追踪到 LOG10 函数的差异。我在 Linux 上使用 gcc/gfortran,在 Windows 上使用 MinGW。
这是一个例子:
PROGRAM FP
REAL VAL1, VAL2, ARG
DATA VAR1 / 12.5663710 /
DATA VAR2 / 10.6640625 /
DATA VAR3 / 1.08791232 /
ARG = VAR1 * VAR2 / VAR3
VAL1 = LOG10 (VAR1 * VAR2 / VAR3)
VAL2 = LOG10 (ARG)
WRITE (*,"(F30.25)") ARG
WRITE (*,"(F30.25)") LOG10(ARG)
WRITE (*,"(F30.25)") VAL1
WRITE (*,"(F30.25)") VAL2
END PROGRAM FP
在 Linux,我得到:
123.1795578002929687500000000
2.0905385017395019531250000
2.0905385017395019531250000
2.0905385017395019531250000
在Windows,我得到
123.1795578002929687500000000
2.0905387401580810546875000
2.0905387401580810546875000
2.0905387401580810546875000
相同的值进入 LOG10,但是 2.09053850 在 Linux 和 2.09053874 在 Windows。这足以导致测试出现实质性问题。我怎样才能在两个平台上获得相同的答案?
我正在使用其他人的 Fortran 代码,我不是其浮点实现细节方面的专家,但通过并排跟踪代码直到值出现分歧,我发现了问题。 LOG10似乎是罪魁祸首。
至于编译器版本,在 Linux 我得到:
$ gfortran --version
GNU Fortran (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
在 Windows:
> gfortran --version
GNU Fortran (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
不同之处在于使用了不同的运行时库。 log10
函数实现并非来自 libgfortran 运行时库。相反,在 Linux 上,标准 C 库 GNU libc (GLIBC) 被称为 https://www.gnu.org/software/libc/manual/html_node/Exponents-and-Logarithms.html(它在 libm 部分)。
其他编译器会有不同的做法。英特尔 Fortran 有自己的运行时库,它实际上在 Linux.
上给出了答案 2.0905387401580810546875000
在 Windows 上,它可能取决于您使用的 GCC 发行版。如果您使用的是 MinGW,则使用 Microsoft C 运行时库而不是 GNU C 库。
据我所知,GLIBC 在 Windows 上根本不可用 (Can I use glibc under windows?)。您可能会尝试从那里获取日志功能,然后 link 它与您的程序一起使用,但您将不得不深入挖掘内部结构。
应该通过将 log10 函数的参数提升为双精度然后将结果转换回单精度来获得跨平台的一致答案。尝试以下功能
`
real function mylog10(rarg)
integer, parameter :: dp = selected_real_kind(15,9)
real, intent(in) :: rarg
mylog10=log10(real(rarg,kind=dp))
end function mylog10
`
我在 Linux 上获得了英特尔和 gfortran 的 2.0905387401580810546875000
。如果在数组上工作,您甚至可以创建函数 elemental
。
我一直在研究需要在 Windows 和 Linux 上 运行 的混合 C++/Fortran 数字代码,并追踪到 LOG10 函数的差异。我在 Linux 上使用 gcc/gfortran,在 Windows 上使用 MinGW。
这是一个例子:
PROGRAM FP
REAL VAL1, VAL2, ARG
DATA VAR1 / 12.5663710 /
DATA VAR2 / 10.6640625 /
DATA VAR3 / 1.08791232 /
ARG = VAR1 * VAR2 / VAR3
VAL1 = LOG10 (VAR1 * VAR2 / VAR3)
VAL2 = LOG10 (ARG)
WRITE (*,"(F30.25)") ARG
WRITE (*,"(F30.25)") LOG10(ARG)
WRITE (*,"(F30.25)") VAL1
WRITE (*,"(F30.25)") VAL2
END PROGRAM FP
在 Linux,我得到:
123.1795578002929687500000000
2.0905385017395019531250000
2.0905385017395019531250000
2.0905385017395019531250000
在Windows,我得到
123.1795578002929687500000000
2.0905387401580810546875000
2.0905387401580810546875000
2.0905387401580810546875000
相同的值进入 LOG10,但是 2.09053850 在 Linux 和 2.09053874 在 Windows。这足以导致测试出现实质性问题。我怎样才能在两个平台上获得相同的答案?
我正在使用其他人的 Fortran 代码,我不是其浮点实现细节方面的专家,但通过并排跟踪代码直到值出现分歧,我发现了问题。 LOG10似乎是罪魁祸首。
至于编译器版本,在 Linux 我得到:
$ gfortran --version
GNU Fortran (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
在 Windows:
> gfortran --version
GNU Fortran (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
不同之处在于使用了不同的运行时库。 log10
函数实现并非来自 libgfortran 运行时库。相反,在 Linux 上,标准 C 库 GNU libc (GLIBC) 被称为 https://www.gnu.org/software/libc/manual/html_node/Exponents-and-Logarithms.html(它在 libm 部分)。
其他编译器会有不同的做法。英特尔 Fortran 有自己的运行时库,它实际上在 Linux.
上给出了答案 2.0905387401580810546875000在 Windows 上,它可能取决于您使用的 GCC 发行版。如果您使用的是 MinGW,则使用 Microsoft C 运行时库而不是 GNU C 库。
据我所知,GLIBC 在 Windows 上根本不可用 (Can I use glibc under windows?)。您可能会尝试从那里获取日志功能,然后 link 它与您的程序一起使用,但您将不得不深入挖掘内部结构。
应该通过将 log10 函数的参数提升为双精度然后将结果转换回单精度来获得跨平台的一致答案。尝试以下功能
`
real function mylog10(rarg)
integer, parameter :: dp = selected_real_kind(15,9)
real, intent(in) :: rarg
mylog10=log10(real(rarg,kind=dp))
end function mylog10
`
我在 Linux 上获得了英特尔和 gfortran 的 2.0905387401580810546875000
。如果在数组上工作,您甚至可以创建函数 elemental
。