Фортран SWITCH построить скорость - PullRequest
0 голосов
/ 04 апреля 2019

Я знаю, что информатика обычно не одобряет высказывания GOTO, но есть ли преимущество в скорости, которое можно получить, используя

    INTEGER WHICH
    GOTO(100,200,300) WHICH
100 do something
    GOTO 400
200 do something else
    GOTO 400
300 do a third thing
    GOTO 400
400 CONTINUE

против

    INTEGER WHICH
    IF(WHICH.EQ.1)THEN
      do something
    ELSEIF(WHICH.EQ.2)THEN
      do something else
    ELSEIF(WHICH.EQ.3)THEN
      do a third thing
    ENDIF

поскольку в Фортране нет оператора SWITCH?

1 Ответ

2 голосов
/ 04 апреля 2019

Прежде всего, в качестве общего комментария, этот тип микрооптимизации не стоит вашего времени.Более важным является ответ на вопрос: Что легче отлаживать, понимать и переносить?

Обязательный пост: GOTO по-прежнему считается вредным?

enter image description here


С учетом вышесказанного я, к сожалению, должен сообщить вам, что у OP есть ошибка в его примерах кода (здесьприходит хищник).Используемая вами вычисляемая инструкция GOTO имеет следующие свойства:

Выполнение вычисленной инструкции GOTO приводит к вычислению целочисленного скалярного выражения.Если это значение равно i , так что 1 ≤ i ≤ n , где n - количество меток в списке меток, происходит переход к целевому оператору переходаидентифицируется по метке i th в списке меток. Если i меньше 1 или больше n , последовательность выполнения продолжается, как если бы выполнялся оператор CONTINUE.

источник: Fortran 2008 Standard

Это означает, что правильная версия должна выглядеть следующим образом:

    INTEGER WHICH
    GOTO(100,200,300) WHICH
    GOTO 400                  << missing part
100 do something
    GOTO 400
200 do something else
    GOTO 400
300 do a third thing
    GOTO 400
400 CONTINUE

Когда вы генерируете код сборки из следующих 3 файлов (см. Ниже), вы фактически заметите, что код сборки идентичен при оптимизации.Вы можете быстро проверить это самостоятельно, используя следующие строки в bash-скрипте:

$ for i in f{1,2,3}.f90; do ifort -O3 -S $i; done
$ meld f{1,2,3}.s

Вы также заметите, что если вы удалите отсутствующий goto 400, код сборки goto будет быстрее нанесколько инструкций.


источник f1.f90:

subroutine g(a)
  integer a
  goto(100,200,300) a
  goto 400
100 call f1()
  goto 400
200 call f2()
  goto 400
300 call f3()
  goto 400
400 continue
end subroutine g

источник f2.f90:

subroutine g(a)
  integer a
  if(a.eq.1)then
     call f1()
  elseif(a.eq.2)then
     call f2()
  elseif(a.eq.3)then
     call f3()
  endif
end subroutine g

источник f3.f90:

subroutine g(a)
  integer a
  select case (a)
  case (1)
     call f1()
  case (2)
     call f2()
  case (3)
     call f3()
  end select
end subroutine g
...