2016-10-28 64 views
1

我有以下一段代碼將矢量x分成幾個數組。根據子程序自變量創建一個常量

subroutine split(n, x, r, v, p, t) 
    implicit none 
    integer, intent(in) :: n 
    double precision, intent(in) :: x(n) 

    integer, parameter :: m = (n + 6)/10 
    ! problem here    1 
    double precision, intent(out) :: r(3, m - 1) 
    double precision, intent(out) :: v(3, m - 1) 
    double precision, intent(out) :: p(3, m) 
    double precision, intent(out) :: t(m) 
    ! code 
end subroutine split 

此代碼不能與消息

Error: Parameter 'n' at (1) has not been declared or is a variable, which does not reduce to a constant expression 

代碼編譯的罰款,如果我手動更改所有m(n + 6)/10但我尋求一個更優雅的方式編譯。

作爲一種替代方法,我已經重寫了代碼

subroutine splitcore(n, m, x, r, v, p, t) 
    implicit none 
    integer, intent(in) :: n, m 
    double precision, intent(in) :: x(n) 
    double precision, intent(out) :: r(3, m - 1) 
    double precision, intent(out) :: v(3, m - 1) 
    double precision, intent(out) :: p(3, m) 
    double precision, intent(out) :: t(m) 
    ! code 
end subroutine splitcore 

subroutine split(n, x, r, v, p, t) 
    implicit none 
    integer, intent(in) :: n 
    double precision, intent(in) :: x(n) 

    integer :: m 
    double precision, intent(out) :: r(3, *) 
    double precision, intent(out) :: v(3, *) 
    double precision, intent(out) :: p(3, *) 
    double precision, intent(out) :: t(*) 

    m = (n + 6)/10 

    call splitcore(n, m, x, r, v, p, t) 
end subroutine split 
+0

您不能使用值初始化常量o f變量。 – Wildcat

回答

1

陣列規格爲在子程序陣列聲明是允許成爲規範表達式。

規範表達式可以包含對純函數的引用。您可以使用這樣一個純函數來計算m的有效計算。

要在其使用範圍內被認爲是純粹的,純函數的顯式接口必須是可訪問的。提供這種明確接口的最簡單方法是將該功能放入模塊中(如果split已經在這樣的模塊中,則該模塊可以是相同的模塊)。

module m_mod 
    implicit none 
contains 
    pure function m(n) 
    integer, intent(in) :: n 
    integer :: m 
    m = (n + 6)/10 
    end function m 
end module m_mod 

subroutine split(n, x, r, v, p, t) 
    use m_mod 
    implicit none 
    integer, intent(in) :: n 
    double precision, intent(in) :: x(n) 

    double precision, intent(out) :: r(3, m(n) - 1) 
    double precision, intent(out) :: v(3, m(n) - 1) 
    double precision, intent(out) :: p(3, m(n)) 
    double precision, intent(out) :: t(m(n)) 
    ... 

在原始代碼的術語 - 初始化爲一個變量,常量或類型參數必須是一個常量表達式 - 有效的東西,編譯器可以在編譯時評估。常量表達式比規範表達式有更多限制 - 例如它不能引用變量的值 - 因爲變量不是常量。

而不是明確的形狀的數組,在split子程序虛擬變量也許可以做出假設形狀(具有(:)(:,:)聲明,以適合的等級。然後陣列的形狀的規格取「(假設「),在子程序split中根本不需要進行形狀計算。

使用具有假定形狀僞參數的子程序需要一個明確的接口,以使程序可以在範圍內訪問程序參考

1

這是不可能的。您只需使用(n + 6)/10而不是m。 Fortran不允許您在數組聲明之前定義任何中間計算。

你甚至不需要一個常量(參數)只是一個變量就足夠了。但這是不允許的。

+0

或者,可以使用'associate'構造來減少混亂。 – Wildcat

+0

@Wildcat,不在問題的上下文中,該值將被用作顯式形狀虛擬參數的規範表達式。 – francescalus

+0

@francescalus,正確。 – Wildcat

1

問題實際上有什麼也沒有與數組聲明。以下簡單代碼段

subroutine split(n, x, r, v, p, t) 
    implicit none 

    integer, intent(in) :: n 
    double precision, intent(in) :: x(n) 
    integer :: m = (n + 6)/10 
end subroutine split 

也不會編譯。因此,即使m被聲明爲變量,它也不能被(n + 6)/10表達式初始化。問題是(n + 6)/10不是一個常量表達式,因爲它包含一個變量n


這當然是可能的聲明變量m第一和(n + 6)/10表達式的值以後分配給它:

subroutine split(n, x, r, v, p, t) 
    implicit none 

    integer, intent(in) :: n 
    double precision, intent(in) :: x(n) 
    integer :: m 

    m = (n + 6)/10 
end subroutine split 

這可用於,例如,分配相應的陣列(其具有聲明爲可分配,當然):

subroutine split(n, x, r, v, p, t) 
    implicit none 

    integer, intent(in) :: n 
    double precision, intent(in) :: x(n) 
    integer :: m 

    double precision, dimension(:, :), allocatable, intent(out) :: r 
    double precision, dimension(:, :), allocatable, intent(out) :: v 
    double precision, dimension(:, :), allocatable, intent(out) :: p 
    double precision, dimension(:), allocatable, intent(out) :: t 

    m = (n + 6)/10 
    allocate (r(3, m-1)) 
    allocate (v(3, m - 1)) 
    allocate (p(3, m)) 
    allocate (t(m)) 
    ! code 
end subroutine split