2015-12-17 49 views
3

在我的代碼中,我有一個以5級數組爲參數的子例程,並使用了一個局部變量,它是一個共享前4個索引的4級數組。從其他數組繼承大小的簡明表示法?

我試圖找到一種更簡潔的方式來表達的大小聲明中

subroutine mysub(momentum) 
    complex, intent(in) :: momentum(:,:,:,:,:) 
    complex :: prefactor(& 
     & size(momentum,1), size(momentum,2), size(momentum,4) & 
     & size(momentum,5)) 
    ... 
end subroutine mysub 

大小聲明的冗長危害可讀性,尤其是當變量名是更長的時間比在這裏。

如果這是八度/ MATLAB寫

prefactor = zeros(size(momentum)([1 2 4 5])) 

不Fortran 90的支持一些類似的簡潔我會預分配prefactor?我知道,它可以使用預處理宏諸如

#define XSIZE2(array,a,b) SIZE(array,a), SIZE(array,b) 
#define XSIZE3(array,a,b,c) SIZE(array,a), SIZE(array,b), SIZE(array,c) 
#define XSIZE4(array,a,b,c,d) SIZE(array,a), SIZE(array,b), SIZE(array,c), SIZE(array,d) 

但引入這樣的定義可能會傷害可讀性超過它可以幫助來解決。

+0

你說「前4個指數」,但使用1,2,4和5.這是正確的嗎? – francescalus

+0

我只保留原文。特別是如果你有理由更喜歡自動數組。 –

回答

3

Fortran的2008年增加了mold符到allocate聲明。如果你有機會到支持此功能的編譯器,你可以嘗試

program main 

    implicit none 

    integer :: a(2,3,4,5,6) 
    integer, allocatable :: b(:,:,:,:) 

    print *, shape(a) 

    allocate(b, mold=a(:,:,:,:,1)) 
    print *, shape(b) 

end program main 

這個片段與英特爾Fortran 2016的工作,更新1

+0

可悲的是不適用於我 - 我必須堅持在項目中使用Fortran 90。我不認爲會有意願改變手寫的makefile,只是爲了在一些地方使用更方便的語法。另外,我更喜歡使用沒有'allocatable'變量的派生形狀。如果a是當前子例程的假定形狀數組參數,我可以寫入'integer :: b(size(a,1),size(a,2),size(a,3),5)'。那裏是否也可以使用'mold'語法? – kdb

+0

我不確定我是否理解您對makefile的關注。只要你使用的是更新版本的編譯器,你的makefile宏(FC,F77,F90)就會選中它。此外,'mold'說明符只能與'allocatable'一起使用。我同意@francescalus - 你發佈的原始代碼對我來說似乎很好。 – pch

1

雖然這可能更多的是評論,那麼如何定義這樣的宏...?

subroutine mysub(momentum) 
    complex, intent(in) :: momentum(:,:,:,:,:) 
#define _(i) size(momentum, i) 
    complex :: prefactor(_(1), _(2), _(4), _(5)) 

它也可以被重複定義的不同的參數,例如:

subroutine mysub(momentum, coeff) 
    complex, intent(in) :: momentum(:,:,:,:,:), coeff(:,:,:) 
#define _(i) size(momentum, i) 
    complex :: prefactor_momentum(_(1), _(2), _(4), _(5)) 
#define _(i) size(coeff, i) 
    complex :: prefactor_coeff(_(1), _(3)) 

如果是確定以使用的可分配數組,我可以如下分配它:

subroutine sub(momentum) 
    complex, intent(in) :: momentum(:,:,:,:,:) 
    complex, allocatable :: prefactor(:,:,:,:) 
    integer :: d(5) 

    d = shape(momentum) 
    allocate(prefactor(d(1), d(2), d(4), d(5))) 

要獲得幾個不同參數的組合宏,可能需要嘗試this approach

#define dim2(A,i1,i2)  size(A,i1), size(A,i2) 
#define dim3(A,i1,i2,i3) size(A,i1), size(A,i2), size(A,i3) 
#define dim4(A,i1,i2,i3,i4) size(A,i1), size(A,i2), size(A,i3), size(A,i4) 

#define _dims(A,_1,_2,_3,_4,NAME,...) NAME 
#define getdims(A,...) _dims(A, __VA_ARGS__, dim4, dim3, dim2)(A,__VA_ARGS__) 

subroutine mysub(momentum) 
    complex, intent(in) :: momentum(:,:,:,:,:) 
    complex :: prefactor2(getdims(momentum, 1, 5)) 
    complex :: prefactor3(getdims(momentum, 1, 3, 5)) 
    complex :: prefactor4(getdims(momentum, 1, 2, 4, 5)) 

它轉換(由cpp -P)到

... 
    complex :: prefactor2(size(momentum,1), size(momentum,5)) 
    complex :: prefactor3(size(momentum,1), size(momentum,3), size(momentum,5)) 
    complex :: prefactor4(size(momentum,1), size(momentum,2), size(momentum,4), size(momentum,5)) 
+0

感謝您的回答,但這仍然讓我對代碼增加了默默無聞。如果我使用宏,我也可以使用我的問題中的'XSIZE'宏。 – kdb

+0

在重新定義宏之前,最好不要這樣做。否則,您可能會收到很多警告。 –

+0

是的,我完全同意你的評論。我的「答案」基本上只是一個評論;)(是的,我們有很多警告:)我也認爲「模具」的方法是最好的(如果你的編譯器支持它)。 – roygvib

1

如果我在意這個簡潔那麼我會被誘惑去與approach of using the mold= specifier與可分配的本地變量。這種語法在所有現代編譯器中都得到了很好的支持,並且可以輕鬆插入到構建過程中。

但是,評論這個答案,你說你更喜歡「派生形狀」而不是可分配的局部變量。讓我們放在一邊,這些方面的最終用途(有一些)沒有什麼區別,並探討這方面。

「派生形狀」是指明確形狀的自動對象。對於這樣的對象,每個等級的範圍必須是規範表達式。作爲這些表達式,您使用SIZE(momentum,1)等。

如果您在語法上受到影響,每個等級的範圍都必須明確給出。所以,真的是任何東西更短,如

complex prefactor(array_extents_spec) ! As an array, say. 

但是,我們可以做其他事情,如果我們再次忽略Fortran 90的要求,沒有前景。

考慮一個自動對象

complex, target :: prefactor_t(SIZE(momentum)/SIZE(momentum,3)) ! rank-1, of desired size 

和陣列

integer extents(4) 
extents = [SIZE(momentum,1), SIZE(momentum,2), SIZE(momentum,4), SIZE(momentum,5)] 

我們可以有邊界指針對象重新映射

complex, pointer :: prefactor(:,:,:,:) 
prefactor(1:extents(1), 1:extents(2), 1:extents(3), 1:extents(4)) => prefactor_t 

其可以是小整潔,甚至如果我們將該範圍數組稱爲e,則更短。

使用使用自動對象的範圍數組的同樣的想法,我們可以使用一個block結構,它允許自動對象可執行語句

complex, intent(in) :: momentum(:,:,:,;,:) 
integer e(5) 
e = SHAPE(momentum) 
block 
    complex prefactor(e(1), e(2), e(4), e(5)) ! Automatic, of desired shape 
end block 

這一切的危險是使事情更加之後只是爲了讓一個聲明有點整潔。總之,如果你想要一些比原來更新的東西,mold=真的是要走的路。但是我不認爲你的原始代碼特別不明確。這裏沒有任何其他建議對我來說似乎更好 - 但隨時可以選擇。