Поиск…


Неявные типы переменных

Когда Fortran была первоначально разработана, память была в отличной форме. Имена переменных и процедур могут содержать не более 6 символов, а переменные часто неявно печатаются . Это означает, что первая буква имени переменной определяет ее тип.

  • переменные, начинающиеся с i, j, ..., n, являются integer
  • все остальные (a, b, ..., h, o, p, ..., z) являются real

Возможны такие программы, как Fortran:

program badbadnotgood
  j = 4
  key = 5 ! only the first letter determines the type
  x = 3.142
  print*, "j = ", j, "key = ", key, "x = ", x
end program badbadnotgood

Вы даже можете определить свои собственные неявные правила с implicit выражением:

! all variables are real by default 
implicit real (a-z)

или же

! variables starting with x, y, z are complex
! variables starting with c, s are character with length of 4 bytes
! and all other letters have their default implicit type
implicit complex (x,y,z), character*4 (c,s) 

Неявная типизация больше не считается лучшей практикой. Очень легко сделать ошибку, используя неявное типирование, поскольку опечатки могут остаться незамеченными, например

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

Эта программа будет успешно работать и делать не то.


Чтобы отключить неявное типирование, можно использовать implicit none оператор.

program much_better
  implicit none
  integer :: j = 4
  real :: x = 3.142
  print*, "j = ", j, "x = ", x
end program much_better

Если мы не использовали implicit none в программе oops выше, компилятор заметил бы сразу, и возникает ошибка.

Арифметическое утверждение if

Арифметический оператор if позволяет использовать три ветви в зависимости от результата арифметического выражения

if (arith_expr) label1, label2, label3

Этот оператор if переносит поток управления на одну из меток кода. Если результатом arith_expr является отрицательная label1 , то если результат равен нулю, используется label2 , и если результат положительный, применяется последняя label3 . Арифметика, if требует всех трех меток, но допускает повторное использование меток, поэтому это утверждение можно упростить до двух ветвей if .

Примеры:

if (N * N - N / 2) 130, 140, 130

if (X) 100, 110, 120

Теперь эта функция устарела с той же функциональностью, предлагаемых в , if заявление и if-else конструкция. Например, фрагмент

    if (X) 100, 110, 120
100 print*, "Negative"
    goto 200
110 print*, "Zero"
    goto 200
120 print*, "Positive"
200 continue

может быть записана как конструкция if-else

if (X<0) then
  print*, "Negative"
else if (X==0) then
  print*, "Zero"
else
  print*, "Positive"
end if

Замена оператора if

    if (X) 100, 100, 200
100 print *, "Negative or zero"
200 continue

может быть

if (X<=0) print*, "Negative or zero"

Неблокирующие конструкторы DO

Конструкция без блока do выглядит так:

    integer i
    do 100, i=1, 5
100 print *, i

То есть, если заявленный оператор терминации не является оператором continue . Существуют различные ограничения на утверждение, которое может использоваться как заявление о завершении, и все это, как правило, очень запутанно.

Такая неблокирующая конструкция может быть переписана в виде блока в виде

    integer i
    do 100 i=1,5
      print *, i
100 continue

или лучше, используя end do терминации заявление,

integer i
do i=1,5
  print *, i
end do

Альтернативный возврат

Альтернативный возврат - это средство контроля потока выполнения при возврате из подпрограммы. Он часто используется как форма обработки ошибок:

real x

call sub(x, 1, *100, *200)
print*, "Success:", x
stop

100 print*, "Negative input value"
stop

200 print*, "Input value too large"
stop

end

subroutine sub(x, i, *, *)
  real, intent(out) :: x
  integer, intent(in) :: i
  if (i<0) return 1
  if (i>10) return 2
  x = i
end subroutine

Альтернативный возврат отмечен аргументами * в списке аргументов подпрограммы.

В call заявлении выше *100 и *200 см операторов , помеченных 100 и 200 соответственно.

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

Синтаксис альтернативного возврата сильно отличается от других форм ассоциации аргументов, и средство вводит управление потоком вопреки современным вкусам. Более приятное управление потоком можно управлять с возвратом целочисленного кода состояния.

real x
integer status

call sub(x, 1, status)
select case (status)
case (0)
  print*, "Success:", x
case (1)
  print*, "Negative input value"
case (2)
  print*, "Input value too large"
end select

end

subroutine sub(x, i, status)
  real, intent(out) :: x
  integer, intent(in) :: i
  integer, intent(out) :: status

  status = 0

  if (i<0) then
    status = 1
  else if (i>10)
    status = 2
  else
    x = i
  end if

end subroutine

Фиксированная исходная форма

Первоначально Fortran был разработан для формата фиксированного формата на основе 80-битной перфокарты:

введите описание изображения здесь

Да. Это строка собственного кода автора.

Они были созданы на перфокартной машине, примерно так:

введите описание изображения здесь

Изображения - это оригинальная фотография автора

Формат, как показано на иллюстрированной образце карты, имел первые пять столбцов, зарезервированных для ярлыков операторов. Первый столбец использовался для обозначения комментариев буквой C. Шестой столбец использовался для обозначения продолжения оператора (путем вставки любого символа, отличного от нуля «0»). Последние 8 столбцов были использованы для идентификации и секвенирования карты, что было очень полезно, если вы уронили свою колоду карт на пол! Кодировка символов для перфокарт имела только ограниченный набор символов и была только в верхнем регистре. В результате программы Fortran выглядели следующим образом:

       DIMENSION A(10)                                                    00000001
C THIS IS A COMMENT STATEMENT TO EXPLAIN THIS EXAMPLE PROGRAM             00000002
       WRITE (6,100)                                                      00000003
 100   FORMAT(169HTHIS IS A RATHER LONG STRING BEING OUTPUT WHICH GOES OVE00000004
      1R MORE THAN ONE LINE, AND USES THE STATEMENT CONTINUATION MARKER IN00000005
      2COLUMN 6, AND ALSO USES HOLLERITH STRING FORMAT)                   00000006
       STOP                                                               00000007
       END                                                                00000008

Косвенный символ также игнорировался везде, за исключением внутренней константы символа Холлерита (как показано выше). Это означало, что пробелы могут возникать внутри зарезервированных слов и констант или полностью пропущены. Это имело побочный эффект некоторых довольно вводящих в заблуждение заявлений, таких как:

       DO 1 I = 1.0

является присвоением переменной DO1I тогда как:

       DO1I = 1,0 

фактически является циклом DO для переменной I


Современный Fortran теперь не требует этой фиксированной формы ввода и разрешает свободную форму с использованием любых столбцов. Комментарии теперь обозначаются a ! который также может быть добавлен к строке оператора. Пробелы теперь не разрешены нигде и должны использоваться как разделители, как и на большинстве других языков. Вышеупомянутая программа может быть написана в современном Fortran как:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH no longer GOES OVER MORE THAN ONE LINE, AND does not need to USE THE STATEMENT CONTINUATION MARKER IN COLUMN 6, or the HOLLERITH STRING FORMAT"

Хотя продолжение старого стиля больше не используется, приведенный выше пример иллюстрирует, что очень длинные утверждения все равно будут возникать. Современный Фортран использует символ & в конце и в начале продолжения. Например, мы могли бы написать выше в более читаемой форме:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH still &
         &GOES OVER MORE THAN ONE LINE, AND does need to USE THE STATEMENT &
         &CONTINUATION notation"

Общие блоки

В ранних формах Fortran единственным механизмом создания глобального хранилища переменных, видимым из подпрограмм и функций, является использование механизма блока COMMON . Это разрешает последовательности переменных быть именами и совместно использоваться.

В дополнение к названным общим блокам может также быть пустой (неназванный) общий блок.

Можно было бы объявить пустой общий блок

common i, j

тогда как именованные блок- variables могут быть объявлены как

common /variables/ i, j

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

       PROGRAM STACKING
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = 0
       READ *, IVAL
       CALL PUSH(IVAL)
       CALL POP(IVAL)
       END

       SUBROUTINE PUSH(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = ICOUNT + 1
       ISTACK(ICOUNT) = IVAL
       RETURN
       END

       SUBROUTINE POP(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       IVAL = ISTACK(ICOUNT)
       ICOUNT = ICOUNT - 1
       RETURN
       END

Общие утверждения могут использоваться для неявного объявления типа переменной и указания атрибута dimension . Такое поведение часто является достаточным источником путаницы. Кроме того, подразумеваемая ассоциация хранения и требования для повторных определений между программными единицами используют использование обычных блоков, подверженных ошибкам.

Наконец, общие блоки очень ограничены в объектах, которые они содержат. Например, массив в общем блоке должен иметь явный размер; выделяемые объекты могут не возникнуть; производные типы не должны иметь инициализацию по умолчанию.

В современном Fortran это совместное использование переменных может быть связано с использованием модулей . Вышеприведенный пример может быть записан как:

module heap
  implicit none
  ! In Fortran 2008 all module variables are implicitly saved
  integer, save :: count = 0
  integer, save :: stack(1023)
end module heap

program stacking
  implicit none
  integer val
  read *, val
  call push(val)
  call pop(val)

contains
  subroutine push(val)
    use heap, only : count, stack
    integer val
    count = count + 1
    stack(count) = val
  end subroutine push

  subroutine pop(val)
    use heap, only : count, stack
    integer val
    val = stack(count)
    count = count - 1
  end subroutine pop
end program stacking

Именованные и пустые общие блоки имеют несколько другое поведение. Отметить:

  • объекты в названных общих блоках могут быть определены изначально; объекты в пробе не должны быть
  • объекты в пустых общих блоках ведут себя так, как будто общий блок имеет атрибут save ; объекты в именованных общих блоках без атрибута save могут стать неопределенными, когда блок не входит в область активного программного блока

Эта последняя точка может быть противопоставлена ​​поведению модульных переменных в современном коде. Все переменные модуля в Fortran 2008 неявно сохраняются и не становятся неопределенными, когда модуль выходит из области видимости. До того, как переменные модуля Fortran 2008, как и переменные в именованных общих блоках, также станут неопределенными, когда модуль выходит из сферы действия.

Назначенный GOTO

Назначенный GOTO использует целочисленную переменную, которой присваивается метка оператора с помощью оператора ASSIGN.

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

Назначенный GOTO устаревает в Fortran 90 и удаляется в Fortran 95 и более поздних версиях. Этого можно избежать в современном коде, используя процедуры, внутренние процедуры, указатели на процедуры и другие функции.

Вычисление GOTO

Вычисленный GOTO позволяет разветвлять программу в соответствии со значением целочисленного выражения.

GOTO (label_1, label_2,... label_n) scalar-integer-expression

Если scalar-integer-expression label_1 scalar-integer-expression равно 1, программа продолжается на метке оператора label_1 , если она равна 2, она переходит к label_2 и т. Д. Если он меньше 1 или больше, чем n программа продолжит следующую строку.

Пример:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

перейдем к метке оператора 20.

Эта форма goto устарела в Fortran 95 и позже, будучи замененной конструкцией select case .

Назначенные спецификаторы формата

До Fortran 95 можно было использовать назначенные форматы для ввода или вывода. Рассматривать

integer i, fmt
read *, i

assign 100 to fmt
if (i<100000) assign 200 to fmt

print fmt, i

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

assign оператор присваивает метку заявление к целочисленной переменной. Эта целочисленная переменная позже будет использоваться в качестве спецификатора формата в заявлении print .

Такое назначение спецификатора формата было удалено в Fortran 95. Вместо этого более современный код может использовать некоторую другую форму управления потоком выполнения

integer i
read *, i

if (i<100000) then
  print 100, i
else
  print 200, i
end if

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

или символьная переменная может использоваться как спецификатор формата

character(29), target :: big_fmt='("This is a big number", I10)'
character(30), target :: small_fmt='("This is a small number", I6)'
character(:), pointer :: fmt

integer i
read *, i

fmt=>big_fmt
if (i<100000) fmt=>small_fmt

print fmt, i

end

Функции выписки

Рассмотрите программу

implicit none
integer f, i
f(i)=i

print *, f(1)
end

Здесь f - функция оператора. Он имеет целочисленный тип результата, принимающий один целочисленный аргумент фиктивного аргумента. 1

Такая функция оператора существует в пределах области, в которой она определена. В частности, он имеет доступ к переменным и именованным константам, доступным в этой области.

Тем не менее, функции оператора подвержены многим ограничениям и потенциально запутывают (смотря на случайный взгляд, как оператор присваивания элемента массива). Важными ограничениями являются:

  • результат функции и фиктивные аргументы должны быть скалярными
  • фиктивные аргументы находятся в той же области, что и функция
  • функции оператора не имеют локальных переменных
  • функции оператора не могут передаваться как фактические аргументы

Основные преимущества функций оператора повторяются внутренними функциями

implicit none

print *, f(1)

contains

  integer function f(i)
    integer i
    f = i
  end function

end

Внутренние функции не подпадают под ограничения, упомянутые выше, хотя, возможно, стоит отметить, что внутренняя подпрограмма может не содержать дополнительной внутренней подпрограммы (но она может содержать функцию оператора).

Внутренние функции имеют свою собственную область действия, но также имеют доступную ассоциацию хостов.


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



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow