在 Fortran 中将运行时 if 替换为编译时 if



我有一个子例程,它在中间包含一个简单的if语句,我想摆脱它。原因是我事先知道该陈述是真还是假,这取决于调用发生的位置,而不是基于输入数据。这更具吸引力,因为它是 1 行,如果这真的没有做太多的话。

现在有一个额外的逻辑输入,它纯粹是为了那个 if 语句,它被调用两次 - 一次用"假",一次用"真"。

从本质上讲,我想在编译期间使 if 语句起作用,但 #ifdef 不允许同一子例程的两种不同用法/配置。

愚蠢的解决方案是完全复制子例程,并让一个实例具有"真"段,而另一个实例仅具有"假"段。

然而,除了这远非优雅(并且有 99.9% 的相似性(之外,一旦将来更改子程序,这是一个麻烦的开端。

我会注意到,我并不是说重载子例程(至少不是在"传统"意义上(,尽管这是相同的一般想法。

所以我的问题是 - 是否有针对这种情况的解决方案,或者我将不得不将其保留为运行时 if 语句并具有额外的逻辑真/假输入?

我正在使用Fortran 90/95。

所以我的理解是代码是这样的:

module mymod
implicit none
contains
subroutine mysub(a, l)
integer, intent(inout) :: a
logical, intent(in) :: l
a = mod(a**3, 53)
if (l) then
a = a + 1
else
a = a - 1
end if
end subroutine mysub
end module mymod

program myprog
use mymod
implicit none
integer :: b
b = 10
call mysub(b, .TRUE.)
print *, b
call mysub(b, .FALSE.)
print *, b
end program myprog

而且您担心mysub子例程的效率不如它所能达到的,因为它有一个 if 语句,即使编译器在编译时知道它每次将采用哪些路径。

在你进一步调查之前,我强烈建议你评估一下这是否必要。您能做的一切都会使代码的可读性降低、可维护性降低,并且充其量只能提供边际性能提升。

您可以编写两个不同的子例程,并将相同的部分放在一个单独的文件中,并将其INCLUDE到两个子例程中,如下所示:

同.inc:

integer, intent(inout) :: n
n = mod(n**3, 53)

子F90:

module mymod
implicit none
contains
subroutine mysub_true(n)
include 'same.inc'
n = n + 1
end subroutine mysub_true
subroutine mysub_false(n)
include 'same.inc'
n = n - 1
end subroutine mysub_false
end module mymod

与预处理器一起,您甚至可以全力以赴:

mysub.inc:

#if PATH == 1
#define SUB_NAME mysub_true
#else
#define SUB_NAME mysub_false
#endif
subroutine SUB_NAME(n)
integer, intent(inout) :: n
n = mod(n**3, 53)
#if PATH == 1
n = n + 1
#else
n = n - 1
#endif
end subroutine SUB_NAME
#undef SUB_NAME
#undef PATH

我的模组。F90:

module mymod
implicit none
contains
#define PATH 1
#include mysub.inc
#define PATH 0
#include mysub.inc
end module mymod

我的计划。F90:

program myprog
use mymod
implicit none
integer :: b
b = 10
call mysub_true(b)
print *, b
call mysub_false(b)
print *, b
end program myprog

并编译使用

gfortran -c -o mymod.o -cpp mymod.F90
gfortran -o myprog myprog.F90 mymod.o

这是否使阅读更容易或更难阅读取决于相同部分的复杂性。

最新更新