Fortran精确默认带/ out编译器标志

时间:2018-06-18 18:38:40

标签: fortran

我在Fortran中遇到常数数字的精度问题。

我是否需要将每个0.1写为0.1d0以获得双倍精度?我知道编译器在gfortran中有一个标记,如-fdefault-real-8,可以解决这类问题。它是一种便携可靠的方式吗?我怎么能检查标志选项是否真的适用于我的代码?

我使用F2py在我的Python代码中调用Fortran代码,即使我给出了一个未指定的标志,它也不报告错误,这就是令我担心的事情。

3 个答案:

答案 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作为子程序参数总是会引起问题,因为这会被转换为实常数。

因此,考虑到如何处理实常数的历史,您需要在需要时明确指定双精度常量。它不是一种用户友好的方法。