【问题标题】:Dummy argument not agreeing with actual argument when passing function传递函数时虚拟参数与实际参数不一致
【发布时间】:2021-04-03 03:23:13
【问题描述】:

我正在尝试实现 Newton 的方法,但收到一条令人困惑的错误消息。在我的代码中,您会看到我用 f1 和 f2 调用 external ,我假设它告诉计算机查找函数,但它根据错误消息将它们视为变量。我已经阅读了与我的问题类似的堆栈溢出帖子,但似乎没有一个解决方案有效。我尝试过使用和不使用外部,但问题仍然存在。希望有人能看到我缺少的东西。

implicit none 

contains 

subroutine solve(f1,f2,x0,n, EPSILON)
implicit none

real(kind = 2), external:: f1, f2
real (kind = 2), intent(in):: x0, EPSILON
real (kind = 2):: x
integer, intent(in):: n
integer:: iteration
x = x0

do while (abs(f1(x))>EPSILON)
  iteration = iteration + 1
  print*, iteration, x, f1(x)
  x = x - (f1(x)/f2(x))
  if (iteration >= n) then 
    print*, "No Convergence"
    stop
  end if  
end do

print*, iteration, x

end subroutine solve

end module newton   

Program Lab10
use newton
implicit none
integer, parameter :: n = 1000  ! maximum iteration
real(kind = 2), parameter :: EPSILON = 1.d-3
real(kind = 2):: x0, x
x0 = 3.0d0

call solve(f(x),fp(x),x0,n, EPSILON) 
  
contains

real (kind = 2) function f(x)  ! this is f(x)
implicit none
real (kind = 2), intent(in)::x
f = x**2.0d0-1.0d0
end function f

real (kind = 2) function fp(x)  ! This is f'(x)
implicit none
real (kind = 2), intent(in)::x
fp = 2.0d0*x
end function fp

end program Lab10```

【问题讨论】:

    标签: fortran


    【解决方案1】:

    您似乎将函数结果传递给您的子例程,而不是函数本身。调用solve()时去掉(x),问题就解决了。但更重要的是,这段代码是如何不在 Fortran 中编程的主要示例。属性external 已弃用,您最好提供一个显式接口。另外kind = 2是什么意思。 Gfortran 甚至不理解它。就算领悟了那种,也不是便携的。这是代码的正确可移植现代实现,

    module newton
    
        use iso_fortran_env, only: RK => real64
        implicit none
    
        abstract interface
            pure function f_proc(x) result(result)
                import RK
                real(RK), intent(in)    :: x
                real(RK)                :: result
            end function f_proc
        end interface
    
    contains
    
        subroutine solve(f1,f2,x0,n, EPSILON)
    
            procedure(f_proc)       :: f1, f2
            real(RK), intent(in)    :: x0, EPSILON
            integer, intent(in)     :: n
            real(RK)                :: x
            integer                 :: iteration
            x = x0
    
            do while (abs(f1(x))>EPSILON)
              iteration = iteration + 1
              print*, iteration, x, f1(x)
              x = x - (f1(x)/f2(x))
              if (iteration >= n) then
                print*, "No Convergence"
                stop
              end if
            end do
    
            print*, iteration, x
    
        end subroutine solve
    
    end module newton
    
    Program Lab10
    
        use newton
    
        integer, parameter  :: n = 1000  ! maximum iteration
        real(RK), parameter :: EPSILON = 1.e-3_RK
        real(RK)            :: x0, x
        x0 = 3._RK
    
        call solve(f,fp,x0,n, EPSILON)
    
    contains
    
        pure function f(x) result(result) ! this is f(x)
            real (RK), intent(in)   :: x
            real (RK)               :: result
            result = x**2 - 1._RK
        end function f
    
        pure function fp(x) result(result) ! This is f'(x)
            real (RK), intent(in)   :: x
            real (RK)               :: result
            result = 2 * x
        end function fp
    
    end program Lab10
    

    如果您希望将nonpure 函数传递给子例程solve(),则删除pure 属性。注意使用real64 来声明64 位(双精度)实数类型。另请注意我如何使用_RK 后缀为实常数分配 64 位精度。另外,请注意,我将指数从实数更改为整数,因为乘法在计算上比取幂更有效。我希望这个答案不仅仅是 Lab10 的解决方案。

    【讨论】:

    • 就像real(2) 是一种不可移植但很常见的类型,我们不能说real(real64) 指的是任何特定的东西。即使存在,也可能不是“双精度”,也可能不是64位。
    • @francescalus 这是真的。如果编译器支持多种具有特定大小的类型,则标准不会指定为常量选择哪一种。但是使用iso_fortran_env至少有一个系统的方法来控制它对应的种类和大小。
    • @jack 我同意,尽管我倾向于在每个可能的程序单元中保留implicit none。通常,人们倾向于从模块中提取特定功能,以便在其他代码库的其他地方使用。
    • 嗨,所以我添加了您在解决方案中删除 (x) 的补救解决方案,但我得到:“错误 997 - 内部函数,例如 F,不能用作实际参数”和“错误 997 - 内部 FUNCTION,例如 FP,不能用作实际参数”作为错误消息。这些是我以前在工作中没有遇到过的新错误消息,所以我不确定如何处理。
    • 你说得对,我使用的是柏拉图,所以代码有点混乱。在将种类值更改为 8 并将迭代初始设置为 0 后,我能够得到我想要的解决方案。感谢您的帮助。
    猜你喜欢
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多