- •Предисловие
- •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. Управление операциями с плавающей точкой
- •Литература
- •Предметный указатель
- •Оглавление
О. В. Бартеньев. Современный ФОРТРАН
end if
end function
end module |
|
program txy |
! Заголовок главной программы |
use ched |
! Ссылка на модуль CHED |
real x, y |
! Объявление данных главной программы |
if(moched( )) then |
! Вызов модульной функции |
x = a |
! Выполняем вычисления, если введенные |
do while(x <= b) |
! данные не содержат ошибок |
y = x * sin(x)
print '(1x, a, f5.2, a, f6.4)', 'x = ', x, ' y = ', y x = x + dx
end do end if
end program txy
2.4. Этапы проектирования программ
Рассмотренный выше порядок создания программы включает этапы составления общей схемы решения задачи, выделения фрагментов и их интерфейсов (входных и выходных данных), разработки алгоритмов для фрагментов и последующего их кодирования. Если теперь их дополнить этапом тестирования и отладки, то получится схема, вполне пригодная для решения простых задач. Однако жизненный цикл крупных программ несколько шире и состоит из этапов:
1.Разработка спецификации.
2.Проектирование программы.
3.Запись программы на языке программирования (кодирование).
4.Отладка и тестирование программы.
5.Доработка программы.
6.Производство окончательного программного продукта.
7.Документирование.
8.Поддержка программы в процессе эксплуатации.
Спецификация содержит постановку задачи, анализ этой задачи и подробное описание действий, которые должна выполнять программа.
Вспецификации отражаются:
•состав входных, выходных и промежуточных данных;
•какие входные данные являются корректными и какие ошибочными;
•кто является пользователем программы и каким должен быть интерфейс;
•какие ошибки должны выявляться и какие сообщения должны выдаваться пользователю;
•какие ограничения имеет программа (например, программа размещения элементов печатной платы может иметь ограничение по числу размещаемых элементов);
42
2. Элементы программирования
•все особые ситуации, которые требуют специального рассмотрения;
•какая документация должна быть подготовлена;
•перспективы развития программы.
На этапе проектирования создается структура программы и для каждого фрагмента выбираются известные или разрабатываются новые алгоритмы. Последние должны быть подвергнуты тщательным исследованиям на предмет их результативности, т. е. способности алгоритма получать требуемые результаты, и эффективности - способности алгоритма получать нужные результаты за приемлемое время.
Параллельно с разработкой алгоритмов решаются вопросы организации данных, т. е. выделяются данные стандартных типов и способы их представления (скаляр или массив), а также разрабатываются новые структуры данных и определяется круг используемых с этими структурами операций. Подходы к решению этих задач во многом зависят от используемого языка программирования, который может быть, например, объектно-ориентированным или модульным. Современный Фортран поддерживает концепции как процедурного, так и модульного программирования (разд. 8.1).
Для каждого фрагмента на этом этапе также создаются полные спецификации по приведенной выше схеме.
Кодирование после разработки проекта программы и необходимых спецификаций является достаточно простой задачей. Когда же первые два этапа в явном виде не присутствуют, то неявно они выносятся на этап кодирования, со всеми вытекающими отсюда последствиями. Впрочем, для сложных задач игнорирование обозначенных выше этапов разработки программы недопустимо.
Тестирование - это запуск программы или отдельного фрагмента с целью выявления в них ошибок. Отладка - процесс локализации и исправления ошибок. В результате тестирования устанавливается, соответствуют или нет разработанные фрагменты и состоящая из них программа сформулированным в спецификациях требованиям. Методы тестирования и отладки рассмотрены, например, в [10].
Для тестирования фрагмента (программы) создаются специальные тестовые наборы входных данных, для которых до запуска фрагмента (программы) вычисляются ожидаемые результаты. Запуск фрагмента выполняется из специально созданной вспомогательной программы, называемой драйвером. Если фрагмент, в свою очередь, вызывает другие фрагменты, работоспособность которых пока еще не проверена, то эти фрагменты заменяются специальными простыми программами, которые имеют тот же интерфейс, что и заменяемые фрагменты, и имитируют их деятельность. Такие программы называются заглушками.
43
О. В. Бартеньев. Современный ФОРТРАН
Тестирование может начинаться с фрагментов низшего уровня. Тогда нам понадобятся только драйверы, поскольку фрагменты более высокого уровня будут вызывать уже проверенные фрагменты. Такая стратегия тестирования называется восходящей. При нисходящей стратегии тестирование начинается с фрагментов высшего уровня. В этом случае понадобятся только заглушки. Обычно при тестировании восходящая и нисходящая стратегии используются совместно.
Проделанная на предшествующих этапах работа, как правило, предоставляет разработчикам достаточный материал, позволяющий сделать выводы о рабочих характеристиках программы и сформулировать предложения по улучшению программы и ее отдельных показателей. Однако не всегда все эти предложения сразу же реализуются и программа с определенными изъянами выходит в свет в качестве программного продукта. Впрочем, если некоторые характеристики серьезно ухудшают качество программы, то придется выполнить ее доработку.
Поддержка программы в процессе эксплуатации имеет целью устранение выявленных пользователями ошибок и адаптацию программного продукта к условиям его эксплуатации. Помимо этого, накапливается материал, необходимый для последующего развития и создания новой версии программы.
2.5. Правила записи исходного кода
Программисты, как правило, со временем вырабатывают свой стиль записи исходного кода, позволяющий им при повторном обращении к программе быстро вспоминать, что она делает и как работает, и при необходимости быстро вносить изменения в программу. Иными словами, программист умеет писать хорошо читаемый и легко изменяемый код. В ряде случаев необходимо, чтобы этот код легко могли бы прочесть и изменить другие программисты, например сопровождающие программу. Итак, за счет каких приемов удается записать хорошо читаемый и легко изменяемый код? Вот некоторые из них:
•программная единица должна содержать достаточный комментарий, позволяющий определить ее назначение, состав входных и выходных данных и выполняемые ей действия. Комментарий, однако, не должен мешать чтению операторов Фортрана;
•комментарий должен пояснять смысл используемых объектов данных;
•все используемые в программной единице данные должны быть явно объявлены. Это правило будет легче выполнить, если ввести в
программную единицу оператор IMPLICIT NONE;
•операторы объявления следует группировать по типам;
•используемые для объектов данных и процедур имена должны напоминать их смысл и указывать на используемый тип. Например, имя
44
2. Элементы программирования
g может быть использовано для обозначения ускорения свободного падения, имя iVectorSize подойдет для указания длины вектора. Понятен смысл и имени pi;
•атрибуты объектов данных следует объявлять в операторах объявления типа, например так:
integer, parameter :: n = 20, m = 10 |
! Размерности матрицы a |
а не так: |
|
integer n, m |
! Этот способ хуже |
parameter (n = 20, m = 10) |
|
•задание размерностей статических массивов лучше выполнять в виде именованных констант. В случае изменения размерности потребуется изменить лишь значение соответствующей константы:
integer, parameter :: m = 10, n = 20 real a(m, n)
•длину символьной именованной константы лучше задавать в виде звездочки, например:
character(*), parameter :: date = '01.01.2000'
•при записи управляющих конструкций следует использовать правило рельефа, состоящее в том, что расположенные внутри конструкции операторы записываются правее образующих эту конструкцию операторов, например операторов IF-THEN-ELSE. Это же правило распространяется на запись определений производных типов и процедур;
•при записи операторов и выражений следует использовать пробелы, например до и после оператора присваивания или логической операции. Не забывайте ставить пробелы и после запятых, например в конструкторе массива. Однако в длинных выражениях пробелы между знаками операций могут быть опущены;
•при создании вложенных конструкций им следует давать имена;
•операторы FORMAT группируются в одном месте, как правило вверху или внизу программной единицы;
•размещенные в одном файле программные единицы должны разделяться пустыми строками;
•программные единицы следует располагать в файле в алфавитном порядке их имен;
•однократно используемые в программе процедуры лучше оформлять как внутренние, следующие после оператора CONTAINS;
•внутренняя функция лучше операторной;
•формальный параметр - массив следует оформлять как массив, перенимающий форму, или как массив заданной формы;
45
О. В. Бартеньев. Современный ФОРТРАН
•внутренние массивы и строки процедур следует оформлять как автоматические объекты;
•не использовать оператор GOTO;
•не применять ассоциирования памяти;
•отказаться от использования нерекомендуемых и устаревших средств Фортрана (прил. 2).
Большинство из приведенных правил рассмотрены в пособии и проиллюстрированы примерами.
46