Замена во время выполнения, если во время компиляции, если в Fortran - PullRequest
0 голосов
/ 30 мая 2018

У меня есть подпрограмма, в середине которой находится простое выражение if, от которого я бы хотел избавиться.Причина в том, что я заранее знаю, будет ли это утверждение истинным или ложным, основываясь на том, где происходит вызов, а не на основе входных данных.Это еще более привлекательно, поскольку это 1-строчная строка, если она действительно не делает слишком много.

В настоящее время существует дополнительный логический ввод, предназначенный исключительно для этого оператора if, и он вызывается дважды - один раз с"false" и один раз с "true".

По сути, я хочу, чтобы оператор if работал во время компиляции, но #ifdef не позволит использовать два разных использования / конфигурации одной и той же подпрограммы.

Глупое решение состоит в том, чтобы полностью скопировать подпрограмму и иметь один экземпляр с сегментом «истина», а другой - только с сегментом «ложь».

Однако, кроме того, это далеко не элегантно(и имеют сходство 99,9%), это открывает проблемы, если подпрограмма будет изменена в будущем.

Я отмечу, что я не имею в виду перегрузку подпрограммы (по крайней мере, не в «традиционной»).смысл этого), хотя это своего рода общая идея.

Так что мой вопрос - есть ли решение этой ситуации, или я будуНужно ли оставлять его как оператор времени выполнения if и иметь дополнительный логический ввод true / false?

Я использую Fortran 90 / 95.

1 Ответ

0 голосов
/ 30 мая 2018

Итак, я понимаю, что код выглядит примерно так:

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

Будет ли это проще илиТруднее читать, зависит от сложности частей, которые одинаковы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...