Here is a minimal program to reproduce my problem:
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
When I compiled this program with gfortran 14.1, I got this error:
test.f90:12:56:
12 | real (kind=kind) :: small = 0.0e-9
| 1
Error: Cannot convert REAL(4) to REAL(0) at (1)
When I remove = 0.0e-9
, then code compiles successfully.
small = 1.0e-9_kind
when kind
came from derived type parameters)?It works with AOCC 4.1 (flang 16.0)! So I think it is gfortran bug (similar to this bug).
So without removing the original question, I changed it to:
Considering the following parameterized derived type:
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
Here, for all real kinds (except the default real kind), the 1.0e-9
literal assigned to the small
component of mytype
will lose accuracy. How I can use the kind
parameter in the small = 1.0e-9
default value assignment (something like small = 1.0e-9_kind
)?
In a literal real constant like 1.0e-9_kind
the kind parameter must be a named constant.
In contrast, some other specifications of kind parameter merely require a constant expression.
Within a derived type definition like
type t(kind)
integer, kind :: kind
real(kind) :: x=1._kind
end type
the kind parameter for the type declaration (real(kind)
) is the "constant expression" requirement whereas 1._kind
is the "named constant" requirement.
Within the derived type definition a kind parameter of the derived type can be used in a constant expression, but it's not a named constant. That is, we can have real(kind)
, but not 1._kind
.
kind
being a constant expression means we can, however, have
type t(kind)
integer, kind :: kind
real(kind) :: x=TINY(REAL(1., kind)) ! Not TINY(1._kind)
end type
You can specify the "most precise" literal constant and use kind
to convert it:
type t(kind)
integer, kind :: kind
real(kind) :: x=REAL(1._real128, kind)
end type
but that's just
type t(kind)
integer, kind :: kind
real(kind) :: x=1._real128
end type
except for cases where compilers have bugs.
Note that this isn't portable: there's no guarantee that real128
is the most precise real. You're assuming it's a valid kind number, though, so whatever process you used to guarantee that you can use to guarantee it's the most precise or desirable.