Вот минимальная программа для воспроизведения моей проблемы:
program test
use iso_fortran_env, only: REAL32
implicit none
type :: matrix (rows, cols, kind)
integer, len :: rows
integer, len :: cols
integer, kind :: kind = REAL32
real (kind=kind), dimension (rows, cols) :: values
real (kind=kind) :: small = 1.0e-9
end type matrix
end program test
Когда я скомпилировал эту программу с помощью gfortran 14.1, я получил следующую ошибку:
test.f90:12:56:
12 | real (kind=kind) :: small = 0.0e-9
| 1
Error: Cannot convert REAL(4) to REAL(0) at (1)
Когда я удаляю = 0.0e-9, код успешно компилируется.
small = 1.0e-9_kind, когда kind получен из параметров производного типа)?Работает с AOCC 4.1 (фланец 16.0)! Так что я думаю, что это ошибка gfortran (аналогично этому багу).
Поэтому, не удаляя исходный вопрос, я изменил его на:
Учитывая следующий параметризованный производный тип:
program test
use iso_fortran_env, only: REAL32, REAL64, REAL128
implicit none
type :: mytype (kind)
integer, kind :: kind = REAL32
real (kind=kind) :: small = 1.0e-9
end type mytype
type (mytype (kind=REAL32)) :: s
type (mytype (kind=REAL64)) :: d
type (mytype (kind=REAL128)) :: q
end program test
Здесь для всех реальных видов (кроме реального вида по умолчанию) литерал 1.0e-9, назначенный компоненту small компонента mytype, потеряет точность. Как я могу использовать параметр kind в назначении значения по умолчанию small = 1.0e-9 (что-то вроде small = 1.0e-9_kind)?
@ Стив Фортран 2003?
@Ученый: Я думаю, это f2003.
@steve: Спасибо за ответ. Я отредактировал свой вопрос. Пожалуйста, прочитайте добавленный раздел РЕДАКТИРОВАНИЯ.
Как вы думаете, что не так с small = 1.0e-9_kind?
@francescalus: и gfortran, и flang выдают мне ошибку. Я думаю, что в 1.0e-9_kindkind должна быть целочисленной константой (например, integer, parameter :: kind = REAL32). Это нормально в стандарте Фортрана? К сожалению, у меня нет компиляторов Intel, nvhpc и/или pgi.





В буквальной реальной константе, такой как 1.0e-9_kind, параметр kind должен быть именованной константой.
Напротив, некоторые другие спецификации параметра типа требуют просто постоянного выражения.
В определении производного типа, например
type t(kind)
integer, kind :: kind
real(kind) :: x=1._kind
end type
параметр kind для объявления типа (real(kind)) — это требование «постоянного выражения», тогда как 1._kind — это требование «именованной константы».
В определении производного типа параметр вида производного типа может использоваться в константном выражении, но это не именованная константа. То есть real(kind) у нас может быть, а 1._kind нет.
kind будучи постоянным выражением, однако, мы можем иметь
type t(kind)
integer, kind :: kind
real(kind) :: x=TINY(REAL(1., kind)) ! Not TINY(1._kind)
end type
Вы можете указать «наиболее точную» литеральную константу и использовать kind для ее преобразования:
type t(kind)
integer, kind :: kind
real(kind) :: x=REAL(1._real128, kind)
end type
но это всего лишь
type t(kind)
integer, kind :: kind
real(kind) :: x=1._real128
end type
за исключением случаев, когда в компиляторах есть ошибки.
Обратите внимание, что это непереносимо: нет никакой гарантии, что real128 является наиболее точным действительным числом. Однако вы предполагаете, что это действительный номер типа, поэтому любой процесс, который вы использовали для гарантии, вы можете использовать, чтобы гарантировать, что он является наиболее точным или желательным.
Я знаю, что REAL128 не портативен (у меня есть устройство M68K максимум REAL80 типа). Фортран гарантирует, что на один реальный вид точнее, чем реальный вид по умолчанию (double precision). На самом деле REAL64 достаточно для моих нужд. Итак, мне приходится использовать явное или неявное приведение из наиболее точного реального вида. Спасибо.
Возможно, вам будет интересно прочитать о том, как можно делать что-то по-другому вне литеральных констант и инициализации по умолчанию.
Я читал (во многих местах) об использовании целочисленного литерального типа и мнемонических типов (например, 1.0_4 против 1.0_REAL32), которые не являются переносимыми. Например, gfortran использует размер хранилища для вида (REAL32=4, REAL64=8, REAL128=16), но процессоры могут использовать другие значения. Поэтому лучше использовать добрые константы из iso_fortran_env или использовать select_real_kind. Мое намерение использовать kind в качестве параметра PDT состоит в том, чтобы разработать библиотеку моделирования океана и позволить пользователям выбирать точность с плавающей запятой (какая-то общая модель). Я знаю, что есть и другие способы сделать это, но я предпочитаю этот метод.
1._4 всегда ошибается; 1._real32 возможно, неправильно. Стремление к переносимости в Фортране (и во всем остальном) — это хорошо, но «переносимость» в Фортране широко понимается неправильно. (Я не говорю, что вы неправы, но это гораздо более широкая тема, чем можно справедливо выразить в комментариях; я приветствую дальнейшие вопросы.)
Функция параметризованного производного типа в Fortran 2018 в gfortran практически не работает. К сожалению, в настоящее время никто не занимается решением проблем. Лучше не использовать PDT с gfortran или использовать другой компилятор, например компиляторы Intel ifx и/или ifort.