2012-12-29 63 views
3

這是試圖解決的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 

回答

5

如此常見的情況下,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 
     !.... 

請注意,我們要定義自我是class(LAE)而非類型;類是類型的超集,在處理可擴展對象(包括具有(重新)可分配組件的可擴展對象)時是必需的。還要注意我們已經添加了隱含的none,它會馬上告訴你B沒有被定義,因此指定了整數索引i,j和k。

一旦N,AB被正確引用爲self的字段,那麼程序的其餘大部分都是正確的。請注意,您必須reshapeLAE1%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  
+0

非常感謝你,這是非常明確的解釋! – northfly

+1

好的調用,但我不同意這是編譯器可以做的最好的。實際的錯誤(未聲明的數組)比糟糕的語句函數要明顯得多。現代Fortran甚至允許聲明函數散佈在可執行文件之間嗎? – agentp

+0

@george:我同意;我可以用gfortran 4.7.2重現錯誤,但ifort 13給了我一個未聲明的數組/函數錯誤'B',並假定'A'是一個外部函數名。語句函數只能在規範部分中使用,但當然會過時。 – sigma