我对 Fortran 代码不太熟悉,想将其与一些 C 代码进行比较。我对一个想要双精度的数组有以下定义(因为我想用双精度比较 Fortran 和 C 代码之间的数字)。
INTEGER :: n = 3
DOUBLE PRECISION, DIMENSION(n, 1) :: grid
后来我有了
grid(1,1) = -2.85697001387280
grid(2,1) = -1.35562617997427
grid(3,1) = 0.00000000000000
通过调试器运行代码,令我惊讶的是,调试器给出了
grid = [-2.8569700717926025, -1.3556262254714966, 0]
仅对单精度正确。我还尝试过 REAL*8、REAL(8) 而不是 DOUBLE PRECISION。我发现下面的代码更令人惊讶
INTEGER :: n = 3
REAL(8) :: mina = 0.5, maxa = 5.0
REAL(8) :: lmina, step
REAL(8), DIMENSION(n,1) :: a
lmina = log(mina)
lmaxa = log(maxa)
step = (lmaxa - lmina) / (n - 1)
DO i=1,n
a(i,1)=lmina+(i-1.0)*step
END DO
创建标量和数组 a,它们精确到双精度并且完全等于 C 代码的数字。为什么在硬编码元素的情况下会有所不同以及如何修复它。
仅供参考,我编译调试版本如下:
gfortran -g -o myfile myfile.f90
@Mike 分配类型类型参数的(或)正确方法如下所示,
use iso_fortran_env, only: IK => int32, RK => real64
integer(IK), parameter :: n = 3_IK
real(RK) :: grid(n, 1)
grid = [-2.8569700717926025_RK, -1.3556262254714966_RK, 0._RK]
切勿使用
REAL*8
、REAL(8)
或 0._8
。这些都是不可移植的,并且在与使用不同设置编译的外部库链接时可能会导致代码崩溃或产生极其难以调试的分段错误。如果在任何地方频繁使用,_8
也很难在代码库中进行更改。相反,为上面的 IK
和 RK
之类的值定义一个与种类无关的标签,并在任何地方使用它们。
请注意,real64
不保证双精度。它仅保证真实值的 64 位容器。使用此通用标签,您可以通过将 real64
更改为其他可能性(例如 real32
或 real128
)来更改代码中所有实际值的精度(或容器)。如果您希望使用任何编译器随时保证双精度(至少 15 位数字),您可能需要使用以下行而不是 real64
模块中的 iso_fortran_env
,
use iso_fortran_env, only: IK => int32
integer, parameter :: RK = selected_real_kind(p = 15, 300)
integer(IK), parameter :: n = 3_IK
real(RK) :: grid(n, 1)
grid = [-2.8569700717926025_RK, -1.3556262254714966_RK, 0._RK]
请参阅 Fortran 参考,了解
selected_real_kind()
内在函数的详细信息。在大多数情况下,至少对于 GNU 和 Intel 编译器来说,使用 selected_real_kind
是多余的,而 iso_fortran_env
提供了一个很好的、可读的、令人满意的结果。