使用Fortran 可选属性时遇到以下情况 对于假设的形状阵列并试图找出最佳(在性能方面)解决方案。 如果有人能给我一个好的提示,我会很高兴的。 请注意,我对可以获得的每个性能增益感兴趣,因为我的数组很大,循环次数和它们的周期更大。
我的情况是使用可选参数进行计算,或者如果它不存在则在其位置使用另一个数组。
subroutine compute(tmat,av,av2)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in),optional :: av2(:)
if(present(av2)) then
tmat = av *av2
else
tmat = av *av
end if
end subroutine compute_transition_matrices_bosonic
在这个简单的例子中,上面的解决方案没问题。然而,我真正的代码要复杂得多。 这意味着例程的内部块可能非常大(数百行),最重要的是包含许多嵌套循环。 可以想象它如下:
if(present(av2)) then
tmat = "function"(av,av2)
else
tmat = "function"(av,av)
end if
其中“function”代表许多操作和循环(因此是“”)。关键在于这两种情况都是相同的操作
if语句,这样我需要编写两次代码。另一种解决方案是检查av2
是否存在于使用位置
代码会产生一些开销,因为这种检查非常(非常)经常完成。
我想知道是否有更聪明的解决方案来解决这个问题。首先,人们可能会想到使用临时变量
complex, :: phi_tmp(:)
if(present(av2)) then
phi_tmp = av2
else
phi_tmp = av
end if
tmat = "function"(av,phi_tmp)
通常在使用可选参数时完成。但这会复制数据,这在我的情况下是一个非常庞大的数组。 因此,我正在考虑使用指针
complex,intent(in),target :: av(:)
complex,intent(in),optional,target :: av2(:)
complex,pointer :: phi_tmp(:)
if(present(av2)) then
phi_tmp => av2
else
phi_tmp => av
end if
tmat = "function"(av,phi_tmp)
但这需要TARGET
和av
的{{1}}属性。在这里,我不确定这是否会导致自编译器以来性能下降
不能再假设av2
和av
在其优化过程中没有别名,即使这两个都具有av2
属性
这样就不会出现混叠问题。此外,如果在调用例程时输入中的参数有效,这意味着什么
没有INTENT(IN)
属性? (这个编译并且有效!)
有没有人对这些问题有一些经验? 有“标准”解决方案吗? (我找不到一个) 什么是最好的解决方案?
答案 0 :(得分:4)
一种方法是对当前和不存在的情况使用不同的子例程。
subroutine compute1(tmat,av)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
call compute2(tmat, av, av) ! Ensure there is an explicit interface for compute2 here
end subroutine
subroutine compute2(tmat,av,av2)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in) :: av2(:)
tmat = "function"(av,av2)
end subroutine
其中既没有可选参数。
这可以添加到使compute
成为这两者的通用。
当然,这并不适用于所有情况,但是intent(in)
av
和av2
中的compute2
属性我们不必担心混叠。
答案 1 :(得分:2)
我建议使用指针的最后一个解决方案,如果实际参数没有target属性就没有问题,指针在例程的退出处将变为未定义,但只要你不将它传递给调用程序无关紧要。
您可以使用其他子例程(例如,内部例程)来执行实际计算,该例程不会知道其参数是别名的,并且基本上,如果它们都具有intent(in)
属性,那没关系。所以不会失去任何表现。
subroutine compute(tmat, av, av2)
implicit none
complex, intent(out) :: tmat(:)
complex,intent(in),target :: av(:)
complex,intent(in),optional,target :: av2(:)
complex,pointer :: phi_tmp(:)
if(present(av2)) then
phi_tmp => av2
else
phi_tmp => av
end if
call compute_internal(tmat, av, phi_tmp)
contains
subroutine compute_internal(tmat, av, av2)
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in) :: av2(:)
.....
end subroutine
end subroutine