- •Предисловие
- •1. Элементы языка
- •1.1. Свободная форма записи программы
- •1.2. Консоль-проект
- •1.2.1. Создание проекта в CVF
- •1.2.2. Создание проекта в FPS
- •1.2.3. Операции с проектом
- •1.2.4. Файлы с исходным текстом
- •1.3. Операторы
- •1.4. Объекты данных
- •1.5. Имена
- •1.6. Выражения и операции
- •1.7. Присваивание
- •1.8. Простой ввод/вывод
- •1.8.1. Некоторые правила ввода
- •1.8.2. Ввод из текстового файла
- •1.8.3. Вывод на принтер
- •1.9. Рекомендации по изучению Фортрана
- •1.10. Обработка программы
- •2. Элементы программирования
- •2.1. Алгоритм и программа
- •2.2. Базовые структуры алгоритмов
- •2.2.1. Блок операторов и конструкций
- •2.2.2. Ветвление
- •2.2.3. Цикл
- •2.2.3.1. Цикл "с параметром"
- •2.2.3.2. Циклы "пока" и "до"
- •2.2.4. Прерывание цикла. Объединение условий
- •2.3. Программирование "сверху вниз"
- •2.3.1. Использование функций
- •2.3.2. Использование подпрограмм
- •2.3.3. Использование модулей
- •2.4. Этапы проектирования программ
- •2.5. Правила записи исходного кода
- •3. Организация данных
- •3.1. Типы данных
- •3.2. Операторы объявления типов данных
- •3.2.1. Объявление данных целого типа
- •3.2.2. Объявление данных вещественного типа
- •3.2.3. Объявление данных комплексного типа
- •3.2.4. Объявление данных логического типа
- •3.3. Правила умолчания о типах данных
- •3.4. Изменение правил умолчания
- •3.5. Буквальные константы
- •3.5.1. Целые константы
- •3.5.2. Вещественные константы
- •3.5.3. Комплексные константы
- •3.5.4. Логические константы
- •3.5.5. Символьные константы
- •3.6. Задание именованных констант
- •3.7. Задание начальных значений переменных. Оператор DATA
- •3.8. Символьные данные
- •3.8.1. Объявление символьных данных
- •3.8.2. Применение звездочки для задания длины строки
- •3.8.3. Автоматические строки
- •3.8.4. Выделение подстроки
- •3.8.5. Символьные выражения. Операция конкатенации
- •3.8.6. Присваивание символьных данных
- •3.8.7. Символьные переменные как внутренние файлы
- •3.8.8. Встроенные функции обработки символьных данных
- •3.8.9. Выделение слов из строки текста
- •3.9. Производные типы данных
- •3.9.1. Объявление данных производного типа
- •3.9.2. Инициализация и присваивание записей
- •3.9.2.1. Конструктор производного типа
- •3.9.2.2. Присваивание значений компонентам записи
- •3.9.2.3. Задаваемые присваивания записей
- •3.9.3. Выражения производного типа
- •3.9.4. Запись как параметр процедуры
- •3.9.5. Запись как результат функции
- •3.9.6. Пример работы с данными производного типа
- •3.9.7. Структуры и записи
- •3.9.7.1. Объявление и присваивание значений
- •3.9.7.2. Создание объединений
- •3.9.8. Итоговые замечания
- •3.10. Целочисленные указатели
- •3.11. Ссылки и адресаты
- •3.11.1. Объявление ссылок и адресатов
- •3.11.2. Прикрепление ссылки к адресатам
- •3.11.3. Инициализация ссылки. Функция NULL
- •3.11.4. Явное открепление ссылки от адресата
- •3.11.5. Структуры со ссылками на себя
- •3.11.6. Ссылки как параметры процедур
- •3.11.7. Параметры с атрибутом TARGET
- •3.11.8. Ссылки как результат функции
- •4. Массивы
- •4.1. Объявление массива
- •4.2. Массивы нулевого размера
- •4.3. Одновременное объявление объектов разной формы
- •4.4. Элементы массива
- •4.5. Сечение массива
- •4.6. Присваивание массивов
- •4.7. Маскирование присваивания
- •4.7.1. Оператор и конструкция WHERE
- •4.7.2. Оператор и конструкция FORALL
- •4.8. Динамические массивы
- •4.8.1. Атрибуты POINTER и ALLOCATABLE
- •4.8.2. Операторы ALLOCATE и DEALLOCATE
- •4.8.3. Автоматические массивы
- •4.9. Массивы - формальные параметры процедур
- •4.9.1. Массивы заданной формы
- •4.9.2. Массивы, перенимающие форму
- •4.9.3. Массивы, перенимающие размер
- •4.10. Использование массивов
- •4.11. Массив как результат функции
- •4.12. Встроенные функции для массивов
- •4.12.1. Вычисления в массиве
- •4.12.2. Умножение векторов и матриц
- •4.12.3. Справочные функции для массивов
- •4.12.3.1. Статус размещаемого массива
- •4.12.3.2. Граница, форма и размер массива
- •4.12.4. Функции преобразования массивов
- •4.12.4.1. Элементная функция MERGE слияния массивов
- •4.12.4.2. Упаковка и распаковка массивов
- •4.12.4.3. Переформирование массива
- •4.12.4.4. Построение массива из копий исходного массива
- •4.12.4.5. Функции сдвига массива
- •4.12.4.6. Транспонирование матрицы
- •4.13. Ввод/вывод массива под управлением списка
- •4.13.1. Ввод/вывод одномерного массива
- •4.13.2. Ввод/вывод двумерного массива
- •5. Выражения, операции и присваивание
- •5.1. Арифметические выражения
- •5.1.1. Выполнение арифметических операций
- •5.1.2. Целочисленное деление
- •5.1.3. Ранг и типы арифметических операндов
- •5.1.4. Ошибки округления
- •5.2. Выражения отношения и логические выражения
- •5.3. Задаваемые операции
- •5.4. Приоритет выполнения операций
- •5.5. Константные выражения
- •5.6. Описательные выражения
- •5.7. Присваивание
- •6. Встроенные процедуры
- •6.1. Виды встроенных процедур
- •6.2. Обращение с ключевыми словами
- •6.3. Родовые и специфические имена
- •6.4. Возвращаемое функцией значение
- •6.5. Элементные функции преобразования типов данных
- •6.6. Элементные числовые функции
- •6.7. Вычисление максимума и минимума
- •6.8. Математические элементные функции
- •6.8.1. Экспоненциальная, логарифмическая функции и квадратный корень
- •6.8.2. Тригонометрические функции
- •6.9. Функции для массивов
- •6.10. Справочные функции для любых типов
- •6.11. Числовые справочные и преобразовывающие функции
- •6.11.1. Модели данных целого и вещественного типа
- •6.11.2. Числовые справочные функции
- •6.12. Элементные функции получения данных о компонентах представления вещественных чисел
- •6.13. Преобразования для параметра разновидности
- •6.14. Процедуры для работы с битами
- •6.14.1. Справочная функция BIT_SIZE
- •6.14.2. Элементные функции для работы с битами
- •6.14.3. Элементная подпрограмма MVBITS
- •6.14.4. Пример использования битовых функций
- •6.15. Символьные функции
- •6.16. Процедуры для работы с памятью
- •6.17. Проверка состояния "конец файла"
- •6.18. Неэлементные подпрограммы даты и времени
- •6.19. Случайные числа
- •6.20. Встроенная подпрограмма CPU_TIME
- •7. Управляющие операторы и конструкции
- •7.1. Оператор GOTO безусловного перехода
- •7.2. Оператор и конструкции IF
- •7.2.1. Условный логический оператор IF
- •7.2.2. Конструкция IF THEN END IF
- •7.2.3. Конструкция IF THEN ELSE END IF
- •7.2.4. Конструкция IF THEN ELSE IF
- •7.3. Конструкция SELECT CASE
- •7.4. DO-циклы. Операторы EXIT и CYCLE
- •7.5. Возможные замены циклов
- •7.6. Оператор STOP
- •7.7. Оператор PAUSE
- •8. Программные единицы
- •8.1. Общие понятия
- •8.2. Использование программных единиц в проекте
- •8.3. Работа с проектом в среде DS
- •8.4. Главная программа
- •8.5. Внешние процедуры
- •8.6. Внутренние процедуры
- •8.7. Модули
- •8.8. Оператор USE
- •8.9. Атрибуты PUBLIC и PRIVATE
- •8.10. Операторы заголовка процедур
- •8.10.1. Общие характеристики операторов заголовка процедур
- •8.10.2. Результирующая переменная функции
- •8.11. Параметры процедур
- •8.11.1. Соответствие фактических и формальных параметров
- •8.11.2. Вид связи параметра
- •8.11.3. Явные и неявные интерфейсы
- •8.11.4. Ключевые и необязательные параметры
- •8.11.5. Ограничения на фактические параметры
- •8.11.6. Запрещенные побочные эффекты
- •8.12. Перегрузка и родовые интерфейсы
- •8.12.1. Перегрузка процедур
- •8.12.2. Перегрузка операций и присваивания
- •8.12.3. Общий вид оператора INTERFACE
- •8.13. Ассоциирование имен
- •8.14. Область видимости имен
- •8.15. Область видимости меток
- •8.16. Ассоциирование памяти
- •8.16.1. Типы ассоциируемой памяти
- •8.16.2. Оператор COMMON
- •8.16.3. Программная единица BLOCK DATA
- •8.17. Рекурсивные процедуры
- •8.18. Формальные процедуры
- •8.18.1. Атрибут EXTERNAL
- •8.18.2. Атрибут INTRINSIC
- •8.19. Оператор RETURN выхода из процедуры
- •8.20. Оператор ENTRY дополнительного входа в процедуру
- •8.21. Атрибут AUTOMATIC
- •8.22. Атрибут SAVE
- •8.23. Атрибут STATIC
- •8.24. Атрибут VOLATILE
- •8.25. Чистые процедуры
- •8.26. Элементные процедуры
- •8.27. Операторные функции
- •8.28. Строка INCLUDE
- •8.29. Порядок операторов и директив
- •9. Форматный ввод/вывод
- •9.1. Преобразование данных. Оператор FORMAT
- •9.2. Программирование спецификации формата
- •9.3. Выражения в дескрипторах преобразований
- •9.4. Задание формата в операторах ввода/вывода
- •9.5. Списки ввода/вывода
- •9.5.1. Элементы списков ввода/вывода
- •9.5.2. Циклические списки ввода/вывода
- •9.5.3. Пример организации вывода
- •9.6. Согласование списка ввода/вывода и спецификации формата. Коэффициент повторения. Реверсия формата
- •9.7. Дескрипторы данных
- •9.8. Дескрипторы управления
- •9.9. Управляемый списком ввод/вывод
- •9.9.1. Управляемый именованным списком ввод/вывод
- •9.9.1.1. Объявление именованного списка
- •9.9.1.2. NAMELIST-вывод
- •9.9.1.3. NAMELIST-ввод
- •9.9.2. Управляемый неименованным списком ввод/вывод
- •9.9.2.1. Управляемый неименованным списком ввод
- •9.9.2.2. Управляемый неименованным списком вывод
- •10. Файлы Фортрана
- •10.1. Внешние и внутренние файлы
- •10.2. Позиция файла
- •10.3. Устройство ввода/вывода
- •10.4. Внутренние файлы
- •10.5. Внешние файлы
- •10.6. Записи
- •10.6.1. Типы записей
- •10.6.2. Записи фиксированной длины
- •10.6.3. Записи переменной длины
- •10.6.4. Сегментированные записи
- •10.6.5. Потоки
- •10.6.6. CR-потоки
- •10.6.7. LF-потоки
- •10.7. Передача данных с продвижением и без
- •10.8. Позиция файла перед передачей данных
- •10.9. Позиция файла после передачи данных
- •10.10. Двоичные последовательные файлы
- •10.11. Неформатные последовательные файлы
- •10.12. Текстовые последовательные файлы
- •10.13. Файлы, подсоединенные для прямого доступа
- •10.14. Удаление записей из файла с прямым доступом
- •10.15. Выбор типа файла
- •11. Операции над внешними файлами
- •11.1. Оператор BACKSPACE
- •11.2. Оператор REWIND
- •11.3. Оператор ENDFILE
- •11.4. Оператор OPEN
- •11.5. Оператор CLOSE
- •11.6. Оператор READ
- •11.7. Оператор ACCEPT
- •11.8. Оператор FIND
- •11.9. Оператор DELETE
- •11.10. Оператор UNLOCK
- •11.11. Оператор WRITE
- •11.12. Оператор PRINT
- •11.13. Оператор REWRITE
- •11.14. Оператор INQUIRE
- •11.15. Функция EOF
- •11.16. Организация быстрого ввода/вывода
- •12.1. Некоторые сведения об объектах ActiveX
- •12.2. Для чего нужен конструктор модулей
- •12.3. Интерфейсы процедур управления Автоматизацией
- •12.4. Идентификация объекта
- •12.5. Примеры работы с данными Автоматизации
- •12.5.1. OLE-массивы
- •12.5.2. BSTR-строки
- •12.5.3. Варианты
- •12.6. Другие источники информации
- •12.7. Как воспользоваться объектом ActiveX
- •12.8. Применение конструктора модулей
- •12.9. Пример вызова процедур, сгенерированных конструктором модулей
- •Приложение 1. Вывод русского текста в DOS-окно
- •Приложение 2. Нерекомендуемые, устаревшие и исключенные свойства Фортрана
- •П.-2.1. Нерекомендуемые свойства Фортрана
- •П.-2.1.1. Фиксированная форма записи исходного кода
- •П.-2.1.2. Оператор EQUIVALENCE
- •П.-2.1.3. Оператор ENTRY
- •П.-2.1.4. Вычисляемый GOTO
- •П.-2.1.5. Положение оператора DATA
- •П.-2.2. Устаревшие свойства Фортрана, определенные стандартом 1990 г.
- •П.-2.2.1. Арифметический IF
- •П.-2.2.2. Оператор ASSIGN присваивания меток
- •П.-2.2.3. Назначаемый GOTO
- •П.-2.2.4. Варианты DO-цикла
- •П.-2.2.5. Переход на END IF
- •П.-2.2.6. Альтернативный возврат
- •П.-2.2.7. Дескриптор формата H
- •П.-2.3. Устаревшие свойства Фортрана, определенные стандартом 1995 г.
- •П.-2.4. Исключенные свойства Фортрана
- •Приложение 3. Дополнительные процедуры
- •П.-3.1. Запуск программ
- •П.-3.2. Управление программой
- •П.-3.3. Работа с системой, дисками и директориями
- •П.-3.4. Управление файлами
- •П.-3.5. Генерация случайных чисел
- •П.-3.6. Управление датой и временем
- •П.-3.7. Ввод с клавиатуры и генерация звука
- •П.-3.8. Обработка ошибок
- •П.-3.9. Аргументы в командной строке
- •П.-3.10. Сортировка и поиск в массиве
- •П.-3.11. Управление операциями с плавающей точкой
- •Литература
- •Предметный указатель
- •Оглавление
2. Элементы программирования
2.1. Алгоритм и программа
Программа выполняет на ЭВМ некоторую последовательность действий, в результате чего должны получаться необходимые результаты. Для составления программы прежде необходимо уяснить суть задачи, а затем уже описать действия, после выполнения которых будут получены сформулированные в задаче цели. Иными словами, необходимо составить алгоритм решения задачи.
Рассмотрим простой пример. Пусть надо составить таблицу значений функции y = x*sinx на отрезке [a, b] с шагом dx. Для решения задачи необходимо выполнить следующие действия:
1°. Начало.
2°. Ввести значения a и b границ отрезка и шаг dx.
3°. Задать x - начальную точку вычислений, приняв x = a. 4°. Пока x ≤ b, выполнять:
вычислить значение функции y в точке x: y = x*sinx; вывести значения x и y;
перейти к следующей точке отрезка: x = x + dx. конец цикла 4:
5°. Конец.
Четвертый пункт алгоритма предусматривает повторное выполнение вычислений y для разных значений аргумента x. Такое повторное выполнение однотипных действий называется циклом. Приведенный цикл завершится, когда значение x превысит b - правую границу отрезка.
Для составления программы, выполняющей предусмотренные алгоритмом действия, надо перевести отдельные шаги алгоритма на язык программирования. Если буквально следовать приведенному алгоритму, то мы получим программу:
read *, a, b, dx |
! Выполняем 2-й шаг алгоритма |
x = a |
! Выполняем 3-й шаг алгоритма |
do while(x <= b) |
! Выполняем 4-й шаг алгоритма |
y = x*sin(x) |
! Вывод x и y |
print *, x, y |
|
x = x + dx |
|
end do |
! Конец цикла |
end |
! Завершаем программу |
Однако, хотя программа записана правильно, работать с ней практически невозможно. Предположим, что вы все же запустили программу для вычислений. Тогда перед вами окажется черный экран, глядя на который вам придется догадаться, что нужно ввести 3 числа. Предположим, что вы догадались и, угадав затем порядок ввода, набрали 0,
26
2. Элементы программирования
1, 0.1. Тогда после нажатия на Enter перед вами появятся два столбика с цифрами и опять придется угадывать, что за числа в них расположены. Запустив эту программу через неделю, вы, конечно, уже ничего не вспомните.
Поэтому нам следует придать программе некоторые иные, не предусмотренные первоначальным алгоритмом свойства. Так, нужно создать диалог для ввода данных, нужно пояснить, каким объектам принадлежат выводимые на экран значения. Иными словами, нужно создать некоторый интерфейс между пользователем и программой. Нужно также проверить правильность ввода данных: левая граница должна быть меньше правой, а шаг dx должен быть больше нуля (в противном случае мы можем получить бесконечный цикл, например если a < b и dx ≤ 0). Вводя подобные проверки, мы повышаем надежность программы. Можно предусмотреть и другие повышающие качество программы мероприятия.
Помимо добавлений таких рабочих характеристик полезно увеличить и требования к оформлению программы: дать программе имя, объявить типы применяемых в вычислениях переменных, привести исчерпывающий комментарий. Можно выполнить запись операторов, имен встроенных процедур и других элементов Фортрана прописными буквами, а запись введенных пользователем имен - строчными. При записи фрагментов программы, например управляющей конструкции DO WHILE ... END DO, следует использовать правило рельефа, состоящее в том, что операторы DO WHILE и END DO начинаются с одной позиции, а расположенные внутри этой конструкции операторы смещаются на одну-две позиции вправо по отношению к начальной позиции записи DO WHILE и END DO. Еще одно полезное правило: после запятой или иного разделителя в тексте программы следует проставлять пробел, т. е. поступать так же, как и при записи текста на родном языке. После ряда дополнений мы можем получить программу:
program txy |
! Заголовок программы |
real a, b, dx, x, y |
! Объявление имен и типов переменных |
real :: dxmin = 1.0e-4 |
|
print *, 'Ввод границ отрезка и шага вычислений' |
|
print *, 'Левая граница: ' |
! Выводим подсказку для пользователя |
read *, a |
! Вводим с клавиатуры значение a и |
print *, 'Правая граница: ' |
! нажимаем на Enter. Так же вводятся |
read *, b |
! другие данные |
print *, 'Шаг вычислений: ' |
|
read *, dx |
|
if(dx < dxmin) stop 'Ошибка при задании шага' |
|
x = a |
! Выполняем 3-й шаг алгоритма |
do while(x <= b) |
! Выполняем 4-й шаг алгоритма |
y = x*sin(x) |
! При записи цикла используем правило рельефа |
print *, 'x = ', x, ' y = ', y |
|
27
О. В. Бартеньев. Современный ФОРТРАН
x = x + dx |
|
end do |
! Завершаем программу txy |
end program txy |
Замечание. CVF и FPS обладают специальной библиотекой процедур DIALOGM, предназначенных для создания диалоговых окон В/В данных. Технология создания диалогов средствами DIALOGM рассмотрена в [1].
Предположим, однако, что после ввода a = 0, b = 1 и dx = 0.1. Тогда для значений x, равных, например, 0.3, 0.4 и 0.5, будет выведен результат:
x = |
3.000000E-01 |
y = |
8.865607E-02 |
x = |
4.000000E-01 |
y = |
1.557673E-01 |
x = |
5.000000E-01 |
y = |
2.397128E-01 |
Каждая выводимая на экран строка является в нашем примере отдельной записью.
Результат вывода понятен, но не очень нагляден. Форму его представления можно улучшить, применив форматный вывод, т. е. задав некоторые правила преобразования выводимых данных. Такие правила задаются дескрипторами преобразований (ДП). Для вывода заключенной в кавычки последовательности символов используем дескриптор A, а вывод значения x выполним на поле длиной в 5 позиций, располагая после десятичной точки две цифры. Для этого нам понадобится дескриптор F5.2. При выводе y используем дескриптор F6.4. Тогда оператор вывода x и y примет вид:
print '(1x, a, f5.2, a, f6.4)', 'x = ', x, ' y = ', y
Результат для тех же значений x будет выглядеть уже более наглядно:
x = .30 |
y = .0887 |
||
x = |
.40 |
y = |
.1558 |
x = |
.50 |
y = |
.2397 |
Заметим сразу, что список ДП открывает дескриптор 1X, который означает задание одного пробела, предваряющего выводимый текст. В FPS при форматном выводе это необходимо, поскольку первый символ каждой записи не печатается и рассматривается как символ управления кареткой. В CVF такой интерпретации первого символа не выполняется и дескриптор 1X можно опустить.
Можно также улучшить и фрагмент программы, предназначенный для ввода данных. Если вы запустите программу, то обнаружите, что после вывода каждой подсказки курсор смещается на начало новой строки. Иными словами, выполняется переход на начало следующей записи. Такого перехода можно избежать, если использовать при выводе подсказки форматный вывод и применить в нем для вывода строки дескриптор A, а вслед за ним дескриптор $ или \ или спецификатор ADVANCE = 'NO'. Правда, последняя опция применима лишь в операторе вывода WRITE.
28