代码之家  ›  专栏  ›  技术社区  ›  zyy

为什么我必须在Fortran中隐式指定函数的双精度返回值?

  •  1
  • zyy  · 技术社区  · 7 年前

    common 块我的代码很简单

    program main
        implicit double precision (p)
        real * 8 :: x, y
        common /yvalue/ y
        x = 3d0
        y = 3d0
        print *, power(x)
    end program main
    
    function power(x)
        implicit none
        real * 8 :: power
        real * 8 :: x, y
        common /yvalue/ y
        power = x ** y
    end function power
    

    但如果我注释掉第二行,它隐式声明以 p 为了达到双精度,编译器抱怨如下

    Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))
    

    我确实得到了返回值 power 默认情况下是单个精度变量,但为什么要声明 权力 real * 8 power 在里面 main

    2 回复  |  直到 7 年前
        1
  •  4
  •   Rodrigo Rodrigues    7 年前

    当您试图在代码中调用的过程(函数或子例程)出现时 外部 program 而且也不是任何协议的一部分 module ,它的名字叫 外部功能 (或子程序)。

    Fortran是一种静态类型语言,因此在编译时必须知道所有变量和函数的类型。因此,如果要在程序中引用外部函数,必须有一种方法让程序知道其返回类型。你有3个( 坏的


    1. 最差的 :依赖一个隐式类型规则,该规则恰好将外部函数的返回类型与调用者中与其标识符关联的类型相匹配(就像您在示例中所做的那样)。

    你为什么不应该那样做? . 它使代码的含义变得模糊,你不知道这个名字指的是什么。在某些情况下,它甚至可能看起来像一个数组变量,而不是一个函数。此外,在这种情况下,编译器不会检查参数的一致性,因此如果没有打开特定的编译器选项,代码将在 运行时 ,或更糟,将给出错误的结果。此外,现在隐式键入很少有用,大多数时候都是自找麻烦。始终使用 implicit none !

    p 将是默认的 real 键入(在编译器中,它是 real(4) real*8 ,编译器将其解释为 real(8) (参见最后一个注释),出现错误。


    1. 坏的

    这就像声明变量一样,如下所示:

    program main
    implicit none
    real*8 :: x, y, power
    

    external 可能适用于像您这样的外部程序。它不仅为过程提供了一些属性(可以作为实际参数传递,从内在过程中消除歧义),还可以使标识符的来源更加清晰。

    program main
    implicit none
    real*8 :: x, y, power
    external :: power
    

    你为什么不应该那样做? 编译器也没有检查参数。这严重限制了与外部函数通信的选项:参数不能假定为形状、假定为秩、多态、参数化、共阵列,也不能在被调用方声明为 allocatable , optional , pointer , target asynchronous volatile 或 value ; 返回类型不能是数组、指针或可分配的;该函数不能作为参数传递,请执行以下操作: elemental pure ,不能在此类上下文中使用。而这一切的原因是缺乏一个 显式接口


    1. 可接受 :指定一个 interface 用于调用方中的外部函数。

    program main
    implicit none
    interface
      real*8 function power(y)
        real*8 :: y
      end function
    end interface
    

    这样,编译器就能够知道声明的所有细节,而我提到的所有限制都不适用。完全自由和代码清晰!

    因为有一个更好的方法,那就是使用 modules


    奖金: 更好 :使用模块。

    program main
      use :: aux_module
      implicit none
      real*8 :: x, y
      common /yvalue/ y
      x = 3d0
      y = 3d0
      print *, power(x)
    end
    
    module aux_module
      implicit none
    contains
      function power(x)
        real*8 :: power
        real*8 :: x, y
        common /yvalue/ y
        power = x ** y
      end
    end
    

    你为什么一定要这么做? 因为对于模块,接口是自动且隐式可用的(代码重复更少,没有限制);模块可以单独重新编译和更新,而不会破坏代码。此外,您可以在模块范围内声明共享变量,并避免使用 common

    program main
      use aux_module
      implicit none
      real*8 :: x
      x = 3d0
      y = 3d0
      print *, power(x)
    end
    
    module aux_module
      implicit none
        real*8 :: y
    contains
      function power(x)
        real*8 :: power
        real*8 :: x
        power = x ** y
      end
    end
    

    甚至可以选择将函数直接包含到 之后 contains . 仅当您不打算在其他程序单元中重用此功能时,才建议使用此功能@伊恩布什的 answer 包括这个案子。

    最后一点:看一看 this answer 看看为什么语法 真实*8 不符合标准,应避免使用。

        2
  •  4
  •   Ian Bush    7 年前

    正如注释中所述,简单地声明函数不仅在其自身的范围内,而且在其被调用的范围内,将解决您的问题。不过,我也不想让您使用普通的隐式键入和完全非标准的real*8

    ian@eris:~/work/stackoverflow$ cat power.f90
    Program power_program
      Implicit None
      Integer, Parameter :: wp = Selected_real_kind( 14, 70 )
      Real( wp ) :: x, y
      x = 3.0_wp
      y = 3.0_wp
      ! Return type and kind of the function power in scope 
      ! due to the implicit interface
      Write( *, '( 3( a, 1x, f0.6, 1x ) )' ) &
           'x =', x, 'y = ', y, 'x**y = ', power( x, y )
    Contains
      Pure Function power( x, y ) Result( r )
        Real( wp ) :: r
        Real( wp ), Intent( In ) :: x
        Real( wp ), Intent( In ) :: y
        r = x ** y
      End Function power
    End Program power_program
    ian@eris:~/work/stackoverflow$ gfortran -std=f2003 -Wall -Wextra -O power.f90
    ian@eris:~/work/stackoverflow$ ./a.out
    x = 3.000000 y =  3.000000 x**y =  27.000000
    ian@eris:~/work/stackoverflow$ 
    
    推荐文章