- •Предисловие
- •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. Управление операциями с плавающей точкой
- •Литература
- •Предметный указатель
- •Оглавление
4. Массивы
Массив - это именованный набор из конечного числа объектов одного типа. Объектами (элементами) массива могут быть данные как базовых, так и производных типов. Используя атрибут PARAMETER, можно задать массив-константу. В отличие от простых переменных, предназначенных для хранения отдельных значений, массив является составной переменной. Также к составным относятся объекты символьного и производного типов.
Массивы, так же как и объекты производного типа, обеспечивают доступ к некоторому множеству данных при помощи одного имени, которое называется именем массива. Также имя массива используется для обеспечения доступа к элементу или группе элементов (сечению) массива.
Массивы могут быть статическими и динамическими. Под статические массивы на этапе компиляции выделяется заданный объем памяти, которая занимается массивом во все время существования программы. Память под динамические массивы выделяется в процессе работы программы и при необходимости может быть изменена или освобождена. К динамическим массивам относятся массивы-ссылки, размещаемые и автоматические массивы. Последние могут появляться только в процедурах.
Память под массивы-ссылки выделяется либо в результате выполнения оператора ALLOCATE, либо после прикрепления ссылки к уже размещенному объекту-адресату. Размещаемые массивы получают память только после выполнения оператора ALLOCATE.
4.1. Объявление массива
Массив характеризуется числом измерений, которых может быть не более семи. Число измерений массива называется его рангом. Число элементов массива называется его размером. Также массив характеризуется
формой, которая определяется его рангом и протяженностью (экстентом)
массива вдоль каждого измерения. Оператор
real b(2, 3, 10)
объявляет массив b ранга 3. Размер массива равен 2*3*10 = 60. Форма массива - (2, 3, 10).
Каждая размерность массива может быть задана нижней и верхней границей, которые разделяются двоеточием, например:
real c(4:5, -1:1, 0:9)
Ранг, форма и размер массивов b и c совпадают. Такие массивы называются согласованными.
Нижняя граница и последующее двоеточие при объявлении массива могут быть опущены, тогда по умолчанию нижняя граница принимается
108
4. Массивы
равной единице. Объявление массива выполняется при объявлении типа либо операторами DIMENSION, ALLOCATABLE и POINTER. Также массив можно объявить в операторе COMMON. Приведем различные способы объявления статического одномерного массива целого типа из 10 элементов.
Можно использовать оператор объявления типа:
integer a(10) |
! или a(1:10) |
Зададим границы в виде константного выражения (что рекомендуется):
integer, parameter :: n = 10 integer a(1:n)
Используем теперь атрибут DIMENSION: integer, dimension(10) :: a
а затем оператор DIMENSION:
integer a dimension a(10)
Приведенные объявления статического одномерного массива определяют массив a из 10 объектов (элементов) с именами a(1), a(2), ..., a(10). Схема расположения элементов массива a в памяти компьютера приведена на рис. 4.1.
Ячейка памяти
a(1) a(2) . . . |
a(10) |
Рис. 4.1. Расположение элементов массива в памяти ЭВМ
Запись a(i) отсылает нас к i-му элементу массива a. Переменную i
называют индексной переменной или просто индексом.
Динамический одномерный массив можно объявить, применяя операторы ALLOCATABLE или POINTER:
real a, b |
|
allocatable a(:) |
! Измерения динамического массива |
pointer b(:) |
! задаются двоеточием (:) |
или атрибуты ALLOCATABLE или POINTER: |
|
real, allocatable :: a(:) |
|
real, pointer :: b(:) |
|
При объявлении |
статического массива может быть выполнена |
его инициализация: |
|
integer a(10) /1, 2, 3, 4, 4, 4, 5, 5, 5, 5/
или с использованием коэффициента повторения:
109
О. В. Бартеньев. Современный ФОРТРАН
integer a(10) /1, 2, 3, 3*4, 4*5/
или с использованием оператора DATA:
integer a(10)
data a /1, 2, 3, 3*4, 4*5/
или с использованием конструктора массива: integer :: a(10) = (/ 1, 2, 3, 4, 4, 4, 5, 5, 5, 5 /)
или с использованием в конструкторе массива циклического списка: integer :: i, j, a(10) = (/ 1, 2, 3, (4, i = 4, 6), (5, i = 7, 10) /)
Во всех приведенных примерах после инициализации массива a
a(1) = 1, a(2) = 2, a(3) = 3, a(4) = 4, a(5) = 4, a(6) = 4, a(7) = 5, a(8) = 5, a(9) = 5, a(10) = 5.
При инициализации необходимо, чтобы число констант в списке значений равнялось числу элементов массива. Используя в операторе DATA неявный цикл, можно инициализировать часть массива.
Одним оператором может быть выполнено объявление более одного массива. Например, оператор
real b(-3:3) /7*1.0/, g2(6:8) |
! Массив g2 не определен |
объявляет два одномерных массива - массив b из семи элементов с именами b(-3), b(-2), ..., b(3) и массив g2 из трех элементов с именами g2(6), g2(7), g2(8). Все элементы массива b равны 1.0.
Пример. Найти сумму элементов одномерного массива. real b(-3:5) /1.1, 2.2, 3.3, 4.4, 5.5, 4*7.8/, s
s = 0.0 |
|
do k = -3, 5 |
|
s = s + b(k) |
|
end do |
|
write(*, *) ' s = ', s |
! s = 47.7 |
! Та же задача решается с применением встроенной функции SUM: |
|
write(*, *) ' s = ', sum(b) |
! s = 47.7 |
Аналогично выполняется объявление двумерного массива:
integer b(2, 4) |
! Статический массив из восьми элементов |
real, pointer :: c(:, :) |
! Динамический массив-ссылка |
Первое объявление определяет двумерный массив b из восьми элементов с именами b(1,1), b(2,1), b(1,2), b(2,2), b(1,3), b(2,3), b(1,4), b(2,4).
Двумерный массив b(1:2, 1:4) можно представить в виде таблицы (рис. 4.2), содержащей 2 строки и 4 столбца.
110
4. Массивы
|
|
|
|
|
|
j |
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
2 |
|
3 |
4 |
|
i |
1 |
b(1, 1) |
b(1, 2) |
b(1, 3) |
b(1, 4) |
|||
|
2 |
b(2, |
1) |
b(2, |
2) |
b(2, 3) |
b(2, |
4) |
Рис. 4.2. Представление двумерного массива в виде таблицы
Память компьютера является одномерной, поэтому элементы двумерного массива b расположены в памяти в линейку так, как это показано на рис. 4.3.
|
|
|
|
|
|
|
|
Ячейка |
1 |
-1 |
2 |
-2 |
3 |
-3 |
4 |
-4 |
памяти |
|
|
|
|
|
|
|
|
|
b(1, 1) |
b(2, 1) |
b(1, 2) |
b(2, 2) |
b(1, 3) |
b(2, 3) |
b(1 ,4) |
b(2, 4) |
|
Рис. 4.3. Расположение элементов двумерного массива в памяти ЭВМ
Запись b(i, j) отсылает нас к j-му элементу массива в его i-й строке, где i и j - индексы массива b.
Во многих языках программирования, например в СИ, элементы двумерного массива располагаются в памяти ЭВМ по строкам, в Фортране
– по столбцам, т. е. быстрее изменяется первый индекс массива. В более общем случае в Фортране для многомерного массива при размещении его элементов в памяти ЭВМ закономерность изменения индексов можно отобразить вложенным циклом (на примере трехмерного массива a(2, 4, 6):
do k = 1, 6 |
|
do j = 1, 4 |
! Быстрее всего изменяется индекс i |
do i = 1, 2 |
размещение в памяти элемента с именем a(i, j, k)
end do end do end do
Иными словами, при размещении многомерного массива в памяти ЭВМ быстрее всего изменяется самый левый индекс массива, затем следующий за ним индекс и т. д.
Это обстоятельство следует учитывать при В/В и инициализации многомерного массива. В случае двумерного массива перечисление значений приведет к инициализации по столбцам (соответствие элемент - значение показано на рис. 4.3):
integer b(2, 4) / 1, -1, 2, -2, 3, -3, 4, -4 /
Инициализация по строкам может быть выполнена оператором DATA: data ((b(i, j), j = 1, 4), i = 1, 2) /1, -1, 2, -2, 3, -3, 4, -4/
111
О. В. Бартеньев. Современный ФОРТРАН
или в конструкторе массива при надлежащем применении функции RESHAPE:
integer :: b(2, 4) = reshape((/ |
|
|
|
& |
1, |
-1 |
2 |
-2 |
& |
3 |
-3 |
4 |
-4 |
/), shape = (/ 2, 4 /), order = (/ 2, 1 /)) |
Пример. Найти произведение положительных элементов двумерного массива.
real b(-2:1, 6:8) /1.1, 2.2, 3.3, 4.4, 5.5, 7*-1.1/, p integer i, j
p = 1.0 do j = 6, 8
do i = -2, 1
if(b(i, j) > 0) p = p * b(i, j) end do
end do
write(*, *) ' p = ', p ! p = 193.2612
! Для вычисления произведения можно применить встроенную функцию PRODUCT: p = product(b, mask = b > 0.0)
write(*, *) ' p = ', p
Замечание. Порядок размещения элементов многомерного массива следует учитывать при организации вложенных циклов. Так, цикл
do j = 6, 8
do i = -2, 1 ! Перебираем элементы очередного столбца массива if(b(i, j) > 0) p = p * b(i, j)
end do end do
отработает быстрее, чем цикл
do i = -2, 1 |
|
do j = 6, 8 |
! Неестественный порядок перебора элементов |
if(b(i, j) > 0) p = p * b(i, j) |
! массива b |
end do |
|
end do |
|
Это объясняется тем, что в первом случае во внутреннем цикле обеспечивается естественная и поэтому более производительная последовательность доступа к элементам массива.
Индексом массива может быть целочисленное выражение:
real :: b(5, 10) = 5.1 |
|
|
|
real :: a(5, 5), c(30), r = 7.0 |
|
|
|
c(int(r)*2 + 1) = 2.0 |
! Индекс массива - целочисленное выражение |
||
a(1, 2) = b(int(c(15)), int(sqrt(r))) |
|
|
|
write(*, *) a(1, 2), b(2, 2) |
! |
5.100000 |
5.10000 |
112