我在Fortran中遇到常数数字的精度问题。
我是否需要将每个0.1
写为0.1d0
以获得双倍精度?我知道编译器在gfortran中有一个标记,如-fdefault-real-8
,可以解决这类问题。它是一种便携可靠的方式吗?我怎么能检查标志选项是否真的适用于我的代码?
我使用F2py在我的Python代码中调用Fortran代码,即使我给出了一个未指定的标志,它也不报告错误,这就是令我担心的事情。
答案 0 :(得分:5)
在Fortran程序中,1.0
始终是默认的实数常量,1.0d0
始终是双精度的文字常量。
然而,"双精度"在不同的背景下意味着不同的东西。
在Fortran环境中"双精度"是指特定种类的真实,其精度高于默认真实种类。在更一般的沟通中,双精度"通常被认为是指与IEEE浮点规范匹配的特定实际64位。
gfortran的编译器标志-fdefault-real-8
表示默认的实际值占用8个字节,很可能是编译器用来表示IEEE双精度的字节。
因此,1.0
是默认的实数常量,而不是双精度文字常量,但默认实数可能恰好与IEEE双精度相同。
像this one这样的问题反映了文字常量中精度的含义。对于那些询问我对-fdefault-real-8
等旗帜的建议的人,我会说要避免它们。
答案 1 :(得分:3)
在我看来,由于双精度定义可以在不同平台和编译器之间进行更改,因此在上面添加@francescalus的响应,使用标准Fortran约定显式声明所需类型的常量是一个好习惯。 ,如下例所示:
program test
use, intrinsic :: iso_fortran_env, only: RK => real64
implicit none
write(*,"(*(g20.15))") "real64: ", 2._RK / 3._RK
write(*,"(*(g20.15))") "double precision: ", 2.d0 / 3.d0
write(*,"(*(g20.15))") "single precision: ", 2.e0 / 3.e0
end program test
用gfortran编译此代码给出了:
$gfortran -std=gnu *.f95 -o main
$main
real64: .666666666666667
double precision: .666666666666667
single precision: .666666686534882
这里,前两行的结果(64位实类的显式请求和双精度类)是相同的。但是,通常情况可能并非如此,双精度结果可能取决于编译器标志或硬件,而real64类型将始终符合64位实类计算,而不管默认的实际类型。
现在考虑另一个场景,其中一个声明一个真实变量是64位的,但是,数值计算是以32位精度完成的,
program test
use, intrinsic :: iso_fortran_env, only: RK => real64
implicit none
real(RK) :: real_64
real_64 = 2.e0 / 3.e0
write(*,"(*(g30.15))") "32-bit accuracy is returned: ", real_64
real_64 = 2._RK / 3._RK
write(*,"(*(g30.15))") "64-bit accuracy is returned: ", real_64
end program test
,它给出了以下输出,
$gfortran -std=gnu *.f95 -o main
$main
32-bit accuracy is returned: 0.666666686534882
64-bit accuracy is returned: 0.666666666666667
即使变量声明为real64
,第一行中的结果仍然是错误的,因为它们不符合双精度类型(您想要的64位)。原因是计算首先在文字常量的请求(默认32位)精度中完成,然后存储在64位变量real_64
中,因此,从更准确的答案获得不同的结果输出中的第二行。
所以底线消息是:使用"下划线"在Fortran中显式声明文字常量的类型总是一个好习惯。约定。强>
答案 2 :(得分:0)
你的问题的答案是:是的,你需要指出常量是双精度。使用0.1是该问题的常见示例,因为4字节和8字节表示是不同的。扩展精度字节都为零的其他常量(例如0.5)没有这个问题。
这是在F90引入Fortran,并导致许多遗留FORTRAN代码的转换和重用问题。在F90之前,双精度a = 0.1的结果可能使用了实数0.1或双0.1常数,尽管我使用的所有编译器都提供了双精度值。在使用已发布的结果测试遗留代码时,这可能是不一致结果的常见来源。经常报告示例,例如PI = 3.141592654本周在论坛的代码中。
然而,使用0.1作为子程序参数总是会引起问题,因为这会被转换为实常数。
因此,考虑到如何处理实常数的历史,您需要在需要时明确指定双精度常量。它不是一种用户友好的方法。