从其他数组继承大小的简洁表示法?
Concise notation for inheriting size from other array?
在我的代码中,我有一个子例程,它以一个 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
冗长的大小声明会影响可读性,尤其是当变量名比此处更长时。
如果这是 octave/matlab,我会通过编写
来预先分配 prefactor
prefactor = zeros(size(momentum)([1 2 4 5]))
Fortran 90 是否支持类似简洁的内容?我知道它可以使用预处理器宏来解决,例如
#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)
但是引入这样的定义可能会损害可读性而不是帮助。
虽然这可能更像是一个注释,但定义一个这样的宏怎么样...?
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) )
Fortran 2008 在 allocate
语句中添加了 mold
说明符。如果你有机会获得支持此功能的编译器,你可以尝试
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
此代码段适用于 Intel Fortran 2016,更新 1。
如果我关心这种简洁性,那么我很想使用带有可分配局部变量的 。这种语法在所有现代编译器中都得到了相当好的支持,应该很容易融入构建过程。
但是,评论该答案时您说您更喜欢 "derived shapes" 而不是可分配的局部变量。让我们撇开这些的最终用途(有一些)几乎没有什么区别,并探讨这方面。
"derived shape" 是指明确形状的自动对象。对于这样的对象,每个等级的范围必须是规范表达式。您使用 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=
确实是您想要比原来更整洁的东西的方法。但是我不认为您的原始代码特别不清楚。 None 这里的其他建议对我来说似乎更好 - 但请随意选择。
在我的代码中,我有一个子例程,它以一个 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
冗长的大小声明会影响可读性,尤其是当变量名比此处更长时。
如果这是 octave/matlab,我会通过编写
来预先分配prefactor
prefactor = zeros(size(momentum)([1 2 4 5]))
Fortran 90 是否支持类似简洁的内容?我知道它可以使用预处理器宏来解决,例如
#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)
但是引入这样的定义可能会损害可读性而不是帮助。
虽然这可能更像是一个注释,但定义一个这样的宏怎么样...?
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) )
Fortran 2008 在 allocate
语句中添加了 mold
说明符。如果你有机会获得支持此功能的编译器,你可以尝试
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
此代码段适用于 Intel Fortran 2016,更新 1。
如果我关心这种简洁性,那么我很想使用带有可分配局部变量的
但是,评论该答案时您说您更喜欢 "derived shapes" 而不是可分配的局部变量。让我们撇开这些的最终用途(有一些)几乎没有什么区别,并探讨这方面。
"derived shape" 是指明确形状的自动对象。对于这样的对象,每个等级的范围必须是规范表达式。您使用 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=
确实是您想要比原来更整洁的东西的方法。但是我不认为您的原始代码特别不清楚。 None 这里的其他建议对我来说似乎更好 - 但请随意选择。