如果在Fortran中,则将运行时if替换为编译时

时间:2018-05-29 23:04:57

标签: fortran

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

现在有一个额外的逻辑输入,纯粹是为了if语句,它被调用两次 - 一次是“false”,一次是“true”。

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

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

然而,除了这与优雅(并且具有99.9%的相似性)之外,一旦子程序在将来改变,这是一个麻烦的开口。

我会注意到,我并不是说重载子程序(至少不是“传统”意义上的),尽管这是一个相同的概念。

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

我正在使用Fortran 90/95。

1 个答案:

答案 0 :(得分:3)

所以我的理解是代码类似于:

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放入两个子程序中,如下所示:

same.inc:

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

sub.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

mymod.F90:

module mymod
    implicit none
contains

#define PATH 1
#include mysub.inc

#define PATH 0
#include mysub.inc

end module mymod

myprog.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

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