【问题标题】:Error: Statement Function is recursive错误:语句函数是递归的
【发布时间】:2012-12-29 03:32:55
【问题描述】:

这是试图求解一个 3*3 的线性方程并打印出结果,但它在注释行中遇到了问题:

我在程序外部定义了模块 LinearSolution,我应该在内部定义它吗?有什么区别?

为什么它说语句是递归的,你知道的,当我将这些语句用作普通子程序而不是模块子程序时,它们被验证是没问题的。

module LinearSolution
    type LAE
        integer::N
        double precision,dimension(:,:),allocatable::A
        double precision,dimension(  :),allocatable::B
    contains
        procedure,nopass::RowReduction
    end type LAE
contains
    subroutine RowReduction
        double precision::C
        do k=1,N
            do i=k+1,N
                if(A(k,k)/=0) then
                    C=A(i,k)/A(k,k)
                    B(i)=B(i)-B(k)*C       !error: Statement Function is recursive
                    do j=k+1,N
                        A(i,j)=A(i,j)-A(k,j)*C   !error: Statement Function is recursive
                    end do
                end if
            end do
        end do

        do k=N,1,-1
            do i=k-1,1,-1
                if(A(k,k)/=0) then
                    C=A(i,k)/A(k,k)
                    B(i)=B(i)-B(k)*C  !error: Statement Function is recursive
                end if
            end do
        end do

        do k=1,N
            if(A(k,k)/=0) then
                B(k)=B(k)/A(k,k)  !error: Statement Function is recursive
            end if
        end do
    end subroutine RowReduction
end module LinearSolution

program TestLAE
    use LinearSolution  !fatal error: cant open module file LinearSolution.mod for reading
    type(LAE)::LAE1
    LAE1%N=3
    allocate(LAE1%B(1:N))
    allocate(LAE1%A(1:N,1:N))
    LAE1%B=(/1,1,1/)
    LAE1%A=(/2,0,0,0,2,0,0,0,2/)
    call LAE1%RowReduction
    print*, LAE1%B(1),LAE1%B(2),LAE1%B(3)
end program

【问题讨论】:

    标签: recursion module fortran fortran90 subroutine


    【解决方案1】:

    通常情况下,implicit none 是您的朋友。

    让我们一次解决一个错误:

    B(i)=B(i)-B(k)*C       !error: Statement Function is recursive
    

    编译器在这种情况下无法识别B;这里没有声明 B 的变量(*),所以它可以做的最好的事情是假设它是一个实值 statement function 将 B 定义为 I 的函数。语句函数节省空间,但定义函数的方式令人困惑内联,但除其他外,它们不能是递归的;在这里,您将根据 B(i) 定义 B(i),这显然失败了。

    (*) 但是!你哭。 B 是我的类型 LAE 中的一个数组字段!是的,但我们不在 LAE 的上下文中;事实上,在这个函数的上下文中,没有 LAE 类型的变量甚至可以使用 B 值。这是因为程序被定义为nopass;您需要有一个变量,该变量是被操作的对象,它属于LAE 类,以便我们可以访问这些字段。看起来像这样:

        type LAE
            !...
        contains
            procedure::RowReduction
        end type LAE
    
    contains
        subroutine RowReduction(self)
            class(LAE), intent(InOut) :: self
            double precision::C
            integer :: i, j, k
            do k= 1, self%N
                do i= k+1, self%N
                    if( self%A(k,k) /= 0 ) then
            !....
    

    请注意,我们必须将 self 定义为 class(LAE) 而不是 type; class 是类型的超集,在处理可扩展对象时需要它,这些可扩展对象包括那些具有(重新)可分配组件的对象。还要注意,我们添加了隐式 none,它会立即告诉您 B 没有定义,因此指定了整数索引 i、j 和 k。

    一旦NAB 被正确引用为self 的字段,那么程序的其余大部分都是正确的。请注意,您必须 reshape 您的 LAE1%A 数组:

    LAE1%A=reshape((/2,0,0,0,2,0,0,0,2/), (/N, N/))
    

    但除此之外,一切似乎都很好。

    module LinearSolution
    implicit none
    
        type LAE
            integer::N
            double precision,dimension(:,:),allocatable::A
            double precision,dimension(  :),allocatable::B
        contains
            procedure::RowReduction
        end type LAE
    
    contains
        subroutine RowReduction(self)
            class(LAE), intent(InOut) :: self
            double precision::C
            integer :: i, j, k
            do k= 1, self%N
                do i= k+1, self%N
                    if( self%A(k,k) /= 0 ) then
                        C = self%A(i,k) / self%A(k,k)
                        self%B(i) = self%B(i)- self%B(k)*C
                        do j=k+1, self%N
                             self%A(i,j) = self%A(i,j) - self%A(k,j)*C
                        end do
                    end if
                end do
            end do
    
            do k = self%N,1,-1
                do i=k-1,1,-1
                    if( self%A(k,k)/=0) then
                        C= self%A(i,k)/ self%A(k,k)
                        self%B(i)= self%B(i)- self%B(k)*C
                    end if
                end do
            end do
    
            do k=1, self%N
                if( self%A(k,k)/=0 ) then
                    self%B(k) = self%B(k) / self%A(k,k)
                end if
            end do
        end subroutine RowReduction
    end module LinearSolution
    
    program TestLAE
        use LinearSolution
        implicit none
    
        integer, parameter :: N = 3
        type(LAE)::LAE1
        LAE1%N=N
        allocate(LAE1%B(1:N))
        allocate(LAE1%A(1:N,1:N))
        LAE1%B=(/1,1,1/)
        LAE1%A=reshape((/2,0,0,0,2,0,0,0,2/), (/N, N/))
        call LAE1%RowReduction
        print*, LAE1%B(1),LAE1%B(2),LAE1%B(3)
    end program
    

    跑步给出:

    $ gfortran -o lae lae.f90 -Wall -std=f2003
    $ ./lae
      0.50000000000000000       0.50000000000000000       0.50000000000000000     
    

    【讨论】:

    • 好电话,虽然我不能同意这是编译器能做的最好的。实际的错误(未声明的数组)比错误的语句函数要明显得多。现代 fortran 甚至允许语句函数散布在可执行文件中吗?
    • @george:我同意;我能够使用 gfortran 4.7.2 重现该错误,但 ifort 13 给了我一个未声明的数组/函数错误 B 并假设 A 是一个外部函数名称。语句函数只允许在规范部分中使用,但当然已经过时了。
    猜你喜欢
    • 1970-01-01
    • 2014-06-25
    • 2010-10-23
    • 2018-03-22
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多