Синтаксис языка Фортран, выражения К простейшим элементам синтаксиса языка относят: константы, имена, знаки и имена операций, метки, ключевые слова.
Имена и ключевые слова
Имя дают константе, переменной, операции, массиву, производному типу данных, классу, конструкции, процедуре, модулю, интерфейсу. Действует следующее соглашение об именах:
- имена состоят из латинских букв, цифр 0¸9, символов «_», «$»;
- первым символом имени может быть только буква или символ «$»;
- строчные и прописные буквы не различаются;
- пробелы и знаки препинания, кириллица, греческие буквы, знаки операций и другие специальные символы в именах недопустимы;
- длина имени не более 31 символа.
Объекты программ, в отличие от однобуквенных математических обозначений (s=v*t), принято именовать со смыслом: Space=Velocity*Time.
Ключевые слова (основные – смотри раздел 8.5) – это имена, используемые в Фортран для операторов, атрибутов, некоторых операций, конструкций, встроенных функций. Правила те же, кроме:
- .true.и другие ключевые слова в логике обрамляются точками;
- целое в диапазоне 1:99999 используют как метку (для format).
В Фортране соглашение о ключевых словах гибкое: нет резервирования, как в Си. Ключевые слова могут использоваться в качестве обычных имен, лишь бы не возникало двусмысленности. Программисту не обязательно помнить все ключевые слова – ему поможет компилятор.
Пример двусмысленности по ключевому слову max
Real :: a=2, b=3, c, max ! max – простая переменная
max=a; C = max(a,b) ! здесь max()- встроенная функция
Ошибка: inconsistent usage of MAX - неподходящее использование слова max.
Константы и переменные встроенных типов
Константу нельзя изменить в процессе исполнения программы, она может быть записана явно как 3.14 или иметь имя, например Pi. Переменная – это именованный объект, значение которого можно изменить.
Имеется пять встроенных типов:
- числовые:целые integer,вещественные real, комплексные complex;
- логические logical;
- строковые (символьные) character.
Таблица 16. Примеры оформления констант разных типов
Тип
| Примеры явных констант
| Разновидности и диапазоны порядков
| Пояснения
| integer
| –2147
| integer*1 *2 *4 ±1010
| Точное значение
| Real
| -1.76 1e7 1.2e7 1.3D+123 1.2Q-1234
| real* 4 10±38 7 цифр real* 8 10±308 17 цифр real*1610± 4932 33 цифры
| Неточное представление, неточное вычисление
| Complex
| (-1.76 , 1)
| Пара вещественных чисел
| Неточно
| Logical
| .true. .false.
| Logical*1 *2 *4
| 1 бит
| character
| ‘х=’ “O’K”
| character*1 до *32767 символов
| Кодировка символов ANSI
| Каждому типу соответствует своя область допустимых значений, особый способ хранения в памяти ПК, объём памяти, набор операций ПК.
Атрибут именованной константы parameter, тип и значение входят в ее описание: real,parameter:: Pi =3.141593.
Выражения
Выражение – осмысленная математическая формула, записанная по правилам языка программирования. В отличие от математики формула записывается в виде строк текста; объекты именуются, значки функций заменены именами функций, которые указаны в описании языка и доступны в помощи. В отличие от других языков программирования, выражение может включать не только переменные, но и массивы. В выражение могут входить:
- константа, переменная, элемент массива;
- массив, секция массива;
- вызов функции с аргументами в скобках, например, cos(х-0.2) ;
- операция с одним операндом, например, –х ;
- операция с несколькими операндами, например, x+y+z ;
- парные круглые скобки ( ), квадратных и фигурных скобок нет.
В зависимости от типов объектов, входящих в выражения, различают:
- арифметические (числовые) выраженияс числовым результатом – выполняются операции над числамицелого, вещественного и комплексного типа, выражения могут быть смешанными;
- логические выражения с логическим результатом: логические операции выполняются над логическими величинами, операции отношения – над числами или строками;
- строковые выражения со строковым результатом – выполняются строковые функции и операция сцепления строк, обозначаемая s//p
Арифметическое выражение
Операнды арифметического (числового) выражения могут быть целого, вещественного или комплексного типа.
Таблица 17. В числовом выражении допускаются операции
Операция
| Порядок
| Пример
| Примечания
| Вычисление функции
|
| sin(X)
| одноместная (унарная) операция
| Возведение в степень
|
| X**2
| несколько подряд – справа налево
| Смена знака
|
| –X
| одноместная (унарная) операция
| Деление, умножение
|
| X/Y, X*Y
| несколько подряд – слева направо
| Сложение, вычитание
|
| X+Y, X-Y
| несколько подряд – слева направо
|
Знаки двуместных операций - возведение в степень, умножение, деление, сложение и вычитание записываются между операндами. В отличие от математики, знак операции умножения опускать нельзя. Численное значение результата зависит от порядка выполнения операций. Если надо, порядок действий изменяют скобки; разрешаются только круглые. В выражении без скобок операции выполняются в порядке старшинства.
В компьютере имеются два комплекта арифметических операций – для целых и для вещественных чисел. Действия над комплексными числами выполняются программно по правилам, известным из математики с помощью команд для вещественных чисел. Фортран автоматизирует выбор комплекта операций, руководствуясь типом операндов. Если операнды однотипны, то этого же типа будет операция и результат. Для операций с операндами разных типов результат всегда в наиболее широком классе из числа операндов. Множества чисел расширяются так:
– целые – *1 *2 *4 байта;
– шире – вещественные - *4 *8 *16 байтов;
– шире – комплексные - дважды по *4 *8 *16 байтов.
Обратите внимание, что выбор из двух разных операций деления производится по общему правилу:
- при делении вещественных чисел в результате – вещественное число, например, 2./3.=0.666667;
- при делении целых чисел в результате – целое число, равное целой части частного, например, 8/3=2 или 2/3=0;
- при делении разнотипных операндов в результате – вещественное число, например, 2./3=>2./3.=0.6666667 или 2/3.=>2./3.=0.666667 .
Операция возведения в степень an и ax вычисляется программно:
- приinteger nоперацияa**nвыполняетсякак n-кратное умножение a*a*a* ..*a, поэтому a**n=0 при n<0 и integer a, например, 3**(-2)=1/3**2=1/9=0;
- при real x операция a**x выполняется как , следовательно, должно быть a > 0 ;
- в общем случае для комплексных a,b Здесь a=r+θi представлено в экспоненциальной форме, Ln – комплексный логарифм.
Все переменные, используемые в выражении, должны быть определены к моменту его вычисления.
При вычислении по формулам следует анализировать ОДЗ, чтобы избегать числовых операций с неопределенным результатом:
- деление на нуль x/0;
- деление нуля на нуль 0/0, 0.0/0.0, 0/0.0, 0.0/0;
- возведение нулевого основания в нулевую или отрицательную степень 0**0 0**(-2);
- недопустимо возведение отрицательного основания в вещественную степень, как в (-8)**(1./3), но -(8**(1./3)) для нечетного 3.
Строковое выражение
Операнды строкового выражения должны быть строкового типа. В строковом выражении допускается только одна операция – сцепление строк (конкатенация). Сцепление обозначается «//», например s=s1//s2, символы в строке s нумеруются слева направо как 1,2,…len(s), len (s1//s2)=len(s1)+len(s2). Подстрока - несколько символов строки подряд. Пример: результат вычисления ab = ab(14:26)//ab(1:13) – строка, в которой меняются местами первая и вторая половины алфавита:
Character*26 :: ab=’abcdefghijklmnopqrstuvwxyz’
Строка после: ab=’nopqrstuvwxyzabcdefghijklm’
Обратите внимание на то, что оператор s1=s1//s2 с повторением s1 слева и справа от “=” имеет смысл только с подстроками. Нужно, чтобы суммарная длина не превышала len(s1). В Фортране строки имеют постоянную длину, а именно ту, что заявлена в её описании.В то же время оператор s1=trim(s1)//s2 вполне осмысленный, если в s1 хвостовых пробелов, не менее чем символов в s2. Функция trim (s1) обрезает хвостовые пробелы.
Логическое выражение
Логическое выражение имеет значение «истина» или «ложь», состоя из:
- логических констант и переменных;
- пяти логических операций с операндами логического типа;
- шести отношений, которые сравнивают либо два числовых выражения, либо два символьных выражения.
Результат вычисления отношения – либо .true. – «истина», либо .false.– «ложь».
Таблица 18. В Фортране шесть операций отношения
Отношения
| Фортран 90, сейчас пишут так
| В стиле Фортран 77, устаревающее
| меньше чем A<b
| a<b
| a .lt. b
| меньше или равно A≤b
| a<=b
| a .le. b
| равно A=b
| k==m
| a .eq. b
| не равно A≠b
| k/=m
| a .ne. b
| больше или равно A≥b
| a>=b
| a .ge. b
| больше чем a>b
| a>b
| a .gt. b
| Отношения вычисляются после вычисления их операндов. Например, при A=2, B=0 для отношения A+3 >B порядок действий такой: сначала вычисляется А+3 и получается 5; затем 5 сравнивается с В, которое равно0; результат вычисления выражения 5>0 – «истина».
Логические операции выполняются после вычисления отношений
Таблица 19.
В Фортране пять логических операций
Операция
| Обозначение
| Старшинство
| Пример
| Отрицание НЕ
| .not.
|
| .not.a
| Конъюнкция И
| .and.
|
| a.and.b
| Дизъюнкция ИЛИ
| .or.
|
| a.or.b
| Эквивалентность
| .eqv.
|
| a.eqv.b
| Неэквивалентность
| .neqv.
|
| a.neqv.b
| Операция .not.a является, как и (–x), одноместной (унарной) и пишется перед операндом, остальные знаки логических операций записываются между операндами. Две логические операции могут следовать в выражении непосредственно друг за другом, только если второй операцией является операция отрицания. Например, допустимо a.and. .not.b.
Операция .not. – одноместная и дает результат «истина», если значение операнда «ложь», и результат «ложь», если значение операнда «истина».
Введем обозначения: T – «истина» и F – «ложь».
Таблица 20.
Таблицы истинности пяти логических операций выглядят как
.AND.
| F
| T
|
| .OR.
| F
| T
| F
| F
| F
|
| F
| F
| T
| T
| F
| T
|
| T
| T
| T
|
.EQV.
| F
| T
|
| .NEQV.
| F
| T
| F
| T
| F
|
| F
| F
| T
| T
| F
| T
|
| T
| T
| F
| | | | | .NOT.
| F
| T
| |
| T
| F
| | | | | | | | | | | | Строки и столбцы таблиц истинности помечены значениям операндов, а на пересечении строки и столбца записан результат двухместной операции
Пример логического выражения: a>3 .and.a<5. Выражение истинно, когда оба отношения истинны, то есть аÎ(3,5).
Сложные выражения вычисляются в следующем порядке: числовые операции или строковые операции; операции отношения; логические операции.
Оператор присваивания
Оператор присваивания записывается в виде: переменная = выражение
В зависимости от типов переменной и выражения различают: числовое присваивание, символьное присваивание, логическое присваивание. Любое присваивание, в отличие от других языков программирования может быть векторным, матричным, конформным. Конформность относится как к операндам выражения, так и к переменной и к выражению между собой. Скаляр конформен массиву любого ранга.
Выполнение оператора состоит в вычислении выражения справа от «=» и присвоения результата переменной слева от «=». После выполнения присваивания прежнее значение переменной утрачивается. В отличие от математических формул знак «=» трактуется не как тождество, а как присваивание. Поскольку выражение вычисляется раньше, чем выполняется присваивание, одно и то же имя может быть указано в операторе одновременно слева и справа от знака «=». Например, k=k+1 означает, что текущее значение переменной k увеличивает на 1. К моменту выполнения оператора переменные, входящие в выражение, должны быть определены.
Тип числового выражения назначается автоматически и если он не совпадет с типом переменной, то выполняется преобразование значения вычисленного выражения к типу переменной.
3.4. Ветвления If и циклы Do
Ветвления – конструкции If
Под блоком в Фортране понимают один или несколько выполняемых операторов внутри составного оператора. Передача управления извне внутрь блока запрещена. Конструкции if различаются по числу блоков 0, 1, 2, 3, …. Для реализации многоблочного разветвления имеется расширение elseif (условие) then , а также конструкция, называемая переключателем Select case по целочисленной или символьной переменной.
Таблица 21.
Двухблочный (структурный) условный оператор
Блок-схема
| Конструкция If
|
| If(логическое_выражение) then
блок_then между then и else
else
блок_else между else и endif
endif
|
Таблица 22.
Одноблочный условный оператор (нет блока_else)
Блок-схема
| Конструкция If
|
| If(логическое_выражение) then
блок_then между then и endif
endif
|
Таблица 23.
Безблочный, по-другому, логический условный оператор
Блок-схема
| Конструкция If
|
| If(логическое_выражение) оператор
Пример
If(x<0) y=abs(x)
По виду блок-схема та же, но в прямоугольнике – единственный простой оператор
| Циклы – конструкции DO
Циклом в программе называют группу (блок) многократно выполняемых операторов. Конструкция do обрамляет цикл
do …
…блок_do…
Enddo
Имеется три разновидности циклов в Фортране:
- бесконечный цикл;
- итеративный цикл (цикл по условию);
- цикл по переменной (с заранее известным числом повторений).
Вспомогательные операторы Exit и Cycle
Во всех трех разновидностях циклов (и только в циклах) можно использовать:
- Exit– досрочный выход из цикла на оператор, непосредственно следующий в тексте за enddo ближайшего охватывающего цикла либо указанного именованного циклаExit имя_цикла;
- Cycle– переход на enddo ближайшего охватывающего цикла либоуказанного именованного циклаCycle имя_цикла .
Таблица 24.
Бесконечный цикл
Блок-схема
| Конструкция Do
|
| do
блок_do, в том числе
if (на_выход)exit
enddo ! только повтор do
| Чтобы выполнение цикла когда-либо закончилось, среди операторов блока_DO бесконечного цикла должен быть хотя бы один exit с условием выхода из цикла.
Таблица 25.
Цикл по условию (итеративный цикл)
Блок-схема
| Конструкция Do
|
| Пока условие выполняется, цикл продолжается
Do while(условие)
блок_do
enddo ! только повтор do
| Цикл по переменной
Переменная в операторе Do– предпочтительнее целая, но также допускается вещественная или вещественная двойной точности. Формула расчета числа повторений цикла .
Начало xn, конец xk и шаг step – константы, переменные или выражения одного из перечисленных типов. Функцияint( ) вычисляет целую часть указанного частного, отбрасывая дробную, без округления. Результат max : max (0, +) => +max (0, –)=> 0 max (0, 0)=> 0 . Таблица 26. Цикл по переменной. Опуская подробности, цикл рисуют так
Блок-схема
| Конструкция Do
|
| do переменная = xn, xk, step
блок_do
enddo
| Цикл не выполнится ни разу, то есть kp=0, если
или
Шаг цикла step регламентируется следующим образом:
- step≠0;
- эквивалентны Do i= 1,10,1 и Do i = 1,10 – по умолчанию step=1;
- если step>0, x возрастает, по окончании цикла x > xk;
- если step<0, x убывает, по окончании цикла x < xk.
Переменная цикла x изменяется по закону арифметической прогрессии. Для понимания того, как это происходит, покажем подробную блок-схему, в которой проясняются все детали и правила для цикла по переменной.
Таблица 27.
Цикл по переменной. Подробная блок-схема цикла.
Подробная блок-схема цикла по переменной
| Блок-схема
| Пояснения
|
| Здесь х – переменная цикла;
xn, xk, step – константы, переменные или выражения.
1) do x=xn,xk,step
2) блок_do
3) enddo
4) конец цикла -продолжение программы
enddo – это пункт (3), включающий в себя три действия:
- изменение переменной x,
- уменьшение k на 1,
- переход к (1).
| В соответствии с подробной блок-схемой цикла по переменной выполнение цикла регламентируется следующими правилами:
- переменная x в цикле do изменяется автоматически по закону арифметической прогрессии – изменять ее в блоке_do запрещено;
- не разрешается входить внутрь блока_do извне, поскольку в этом случае не определеночисло повторений цикла kp и переменная x;
- переменные xn, xk, step можно изменять в цикле – это не повлияет на число повторений уже запущенного цикла;
- оператор cycle, встретившийся в блоке_do, прерывает пункт (2) и вызывает переход к end do – пункту (3);
- оператор Exit, встретившийся в блоке_do, прерывает цикл, завершает его досрочно и вызывает переход к пункту (4) – на оператор непосредственно следующий в тексте за end do;
- при нормальном завершении цикла переменная x достигает значения x = xn + step *kp, а при досрочном выходе сохраняется достигнутое значение x из [xn,xk].
Цикл по вещественной переменной x имеет неустойчивый характер:
- при некоторых xn, xk, step цикл выполняется для значения x = xk;
- при других xn, xk, step цикл пропускает последнее значение x = xk.
Причина: ошибка в вычислении kp и накопление погрешности округления в x=x+step, особенно при сравнительно малом step по отношению к x.
Такой цикл можно скорректировать, возможны три варианта:
- переделать радикально – построить цикл по целой переменнойinta, через которую выразить вещественную переменную x. Количество повторений kp при этом следует рассчитать самостоятельно перед циклом; int будет изменяться точно, x не станет накапливать погрешность, хотя разовая погрешность сохранится
integer inta,kp; real x
kp = . . .! количество повторений цикла
do int = 0, kp-1 ! kp – число повторений цикла
x = xn + inta * step
! содержимое прежнего блока_do
Enddo
- «подправить» цикл по вещественной переменной, «обманув» do и переписав его так: do x = xn, xk + step/2, step
- выбрать шаг в виде числа, которое является степенью двойки и точно представляется в памяти компьютера, например, 4, 8, 0.25
Среди операторов блока_do может встретиться другая конструкция do. В этом случае говорят о вложенном цикле. Оценивая количество повторений оператора write внутри вложенного цикла в примере, показанном ниже, необходимо помнить, что при каждом повторении внешнего цикла, внутренний цикл повторяется заново.
Пример вложенных конструкций do
DO y = -1., 1., 0.125 ! 17 раз
do x = -1., 1., 0.125 ! 17 раз
WRITE(1,*) x,y ! 289=17*17 раз
Enddo
ENDDO
В файл будет выведена 289 пар значений х и y.
3.5. Параллельные конструкции where и forall
Условия во вновь появившихся конструкциях Фортрана-95 стали векторными, матричными (в общем случае многомерными). Появилась возможность их варьировать покомпонентно. Прежние управляющие конструкции Do While,If иSelect case, ориентированные на скаляры, для этих целей не подошли. Условия в управляющих конструкцияхдолжны быть конформны проводимым вычислениям, см. раздел 5. Новые управляющие конструкции как раз реализуют параллельныедействия над компонентами векторов и матриц (вообще, массивов) под управлением компонент конформной им маски, заданной логическим выражением. Имеется лишь две конструкции: where иforall(появилась в Fortran-95).
Оператор и конструкция where
Ветвлениеwhereпо формезаписываетсяаналогичноif в трёх разновидностях с количеством блоков два, один, ноль
Таблица 28.
Сравнение операторов if и where
Оператор if
| Оператор where
| if (скаляр-условие) then !2 блока...!блок ДА else if ....!блок НЕТ end if
| where (конформное_условие ) !Два блока ....!блок ДА - _действия, конформные условию else where .... !блок НЕТ - действия, конформные условию end where
| if (скаляр-условие) then !1 блок ...!блок ДА end if
| where (конформное_условие ) !Один блок ....!блок ДА - действия, конформные условию end where
| if (скаляр-условие) !один простой ! без блоков
| where(конформное_условие ) !один конформный !без блоков
| Отметим внешнее сходство if и where–оба ветвления. Однако между ними есть кардинальные отличия:
- if задает скалярное ветвление, группируя действия над скалярами или векторами целиком;
- where– это векторное покомпонентное ветвление, котороегруппирует параллельные действия над компонентами векторов, матриц, многомерных массивов, секций с непременным требованием конформности условия и действий.
Имеется также определенное сходство whereс do – оба могут обрабатывать массивы. Правда, do может задавать закон изменения лишь одного индекса массива по какому-либо измерению, а whereобеспечивает работу по всем компонентам массива независимо, не важно, сколько в нем измерений. Следует подчеркнуть, что имеется принципиальное различиеdo иwhere:
- Do обрабатывает компоненты вектора последовательно;
- where обрабатывает компоненты вектора независимо, параллельно.
Так что where - это вовсе не цикл, а перечисление потенциально параллельных процессов. Реально параллельность достигается только в случае распараллеливающего компилятора и наличия многих процессоров. В случае, когда компилятор не умеет распараллеливать,конструкцияwhere для одномерного массива как бы заменяет do и if.
Порядок действий, соответствующих where:
- вычисляется конформная маска;
- затем над всеми элементами конформных массивов выполняются конформные действия - одно или несколько в последовательности заданной в блоке where;
- действия выполняются только для истинных значений в маске;
- действия выполняются параллельно.
Как всегда, параллельность – это прежде всего независимость процессов, потенциальная способность – в том смысле, что это станет реальностью:
- если будет использован распараллеливающий компилятор IFC;
- если процессоров будет предостаточно;
- если процессоров будет недостаточно, то поочередно пачками, как решит компилятор и операционная система;
- ввиду многих задач и многих пользователей ситуация по числу свободных процессоров может меняться, что затрудняет наши измерения времени решения задачи;
- если компилятор не распараллеливает или процессор единственный, то действия выполняются поочередно по всем элементам, правда, программа выглядит короче.
Пример: найти сумму обратных величин матрицы. Приведем три варианта решения.
1. Рассмотрим сначала на первый взгляд простое решение, которое можно охарактеризовать как “ловушку для начинающих”
RealSumObr
Real,dimension(1:10,1:10) :: A
SumObr=Sum( 1/A, A/=0 )
Ошибка состоит в непонимании порядка действий
- сначала вычисляем аргумент 1/A и рискуем ”поделить на 0” для нулевой компоненты вектора A;
- потом суммируем по маске A/=0.
2. Вычисление обратной величины Obr логично выполнить в виде двухблочной конструкции where
RealSumObr
Real,dimension (1:10,1:10):: A, Obr
where (A/=0 ) !сдвумя блоками
Obr=1/A ! где можно – вычислить обратную величину
else where Obr=0 ! где нельзя – обнулить обратную величину end where
SumObr=Sum(Obr)
3. Вычисление обратной величины можно выполнить и в виде простого оператора where
Real SumObr
real,dimension(1:10,1:10) :: A,Obr
Obr=0;
where (A/=0) Obr=1/A ! безблочный оператор
SumObr=Sum(Obr)
|