【问题标题】:Different results for LOG10 in Fortran on Windows and LinuxWindows 和 Linux 上 Fortran 中 LOG10 的不同结果
【发布时间】:2019-11-18 23:35:59
【问题描述】:

我一直在研究需要在 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

【问题讨论】:

标签: fortran precision gfortran


【解决方案1】:

不同之处在于使用不同的运行时库。 log10 函数实现并非来自 libgfortran 运行时库。相反,在 Linux 上,标准 C 库 GNU libc (GLIBC) 称为 https://www.gnu.org/software/libc/manual/html_node/Exponents-and-Logarithms.html(它位于 libm 部分)。

其他编译器会做不同的事情。 Intel Fortran 有自己的运行时库,它实际上在 Linux 上给出了答案 2.0905387401580810546875000。

在 Windows 上,它可能取决于您使用的 GCC 发行版。如果您使用的是 MinGW,则使用 Microsoft C 运行时库而不是 GNU C 库。

据我所知,GLIBC 在 Windows 上根本不可用 (Can I use glibc under windows?)。您可能会尝试从那里获取日志功能并将其与您的程序链接,但您必须深入挖掘内部结构。

【讨论】:

  • 这很有趣,并引发了一大堆关于跨平台编写数字一致代码的问题。更复杂的是,我的 HP 计算器给出了 2.090538640692396153936101503375651,拆分结果之间的差异。
  • @AndreasYankopolus 计算器的值将是双倍甚至更高的精度。对于 Fortran 中更高的数值精度,请使用双精度,在有限的情况下,甚至可能需要四倍精度。友好的表示法是最好的方法stackoverflow.com/questions/838310/fortran-90-kind-parameter 我希望 GLIBC 和 Microsoft 之间仍然会有一些差异,即使是双精度。只是更小。
【解决方案2】:

应该通过将 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 上得到了 Intel 和 gfortran 的 2.0905387401580810546875000。如果处理数组,您甚至可以创建函数 elemental

【讨论】:

  • 谢谢——这在很大程度上是我最终解决问题的方式。出于种种原因,我不想更改 FORTRAN 代码,所以我用-fdefault-real-8 编译它,并在调用 C++ 代码中进行了 float->double->float 转换。
猜你喜欢
  • 2018-07-06
  • 1970-01-01
  • 2018-01-10
  • 2013-05-20
  • 2020-08-01
  • 2021-07-16
  • 2015-05-04
  • 2011-04-24
  • 1970-01-01
相关资源
最近更新 更多