Reputation: 53
The following small code doesn't work:
program main
implicit none
integer, parameter :: dp=selected_real_kind(15)
real(dp) :: v(9)
real(dp) :: vector_norm
v(:) = 3.14_dp
print *, 'Vector norm = ', vector_norm(9,v)
end program main
function vector_norm(n,vec) result(norm)
integer, intent(in) :: n
real(dp), intent(in) :: vec(n)
real(dp) :: norm
norm = sqrt(sum(vec**2))
end function vector_norm
in the main program, I am creating a kind variable dp
such that everything will be double precision and I want function vector_norm
to yield a double precison result too. I know I can simply use double precision function
instead of function
statement. Can any of you help how to solve that error while keep using selected_real_kind statement.
Note: error is "A kind type parameter must be a compile-time constant."
Upvotes: 3
Views: 188
Reputation: 1524
This works as intended. The trick is the place the function definition inside the program code block by adding the contains
keyword. This way the function code block has access to the variables and parameters of the main program.
program FortanConsole1
implicit none
integer, parameter :: dp=selected_real_kind(15)
real(dp) :: v(9)
v(:) = 3.14_dp
print *, 'Vector norm = ', vector_norm(9,v)
contains
function vector_norm(n,vec) result(norm)
integer, intent(in) :: n
real(dp), intent(in) :: vec(n)
real(dp) :: norm
norm = sqrt(sum(vec**2))
end function vector_norm
end program
No need to define vector_norm
as an external or the type in the main program if it is defined after the contains
keyword. Also no need to define a module for the same effect. Also no need for implicit none
in the function as it falls under the scope of the program which already has this declaration.
BTW, Any function after contains
can access the variables/parameters of the program to avoid duplication (dp
in this case).
Removed the array size from vector_norm
and used an assumed shape array (any length). This simplifies the API to the function.
program FortanConsole1
...
print *, 'Vector norm = ', vector_norm(v)
contains
function vector_norm(vec) result(norm)
real(dp), intent(in) :: vec(:)
...
end function vector_norm
end program FortanConsole1
Upvotes: 1
Reputation: 32366
The things which define the type parameters and array bounds of objects are known as specification expressions. In the code of the question we see two such specification expressions with real(dp) :: v(9)
: the kind type parameter dp
and the array bound 9
.
For a specification expression, only its value matters. Although we don't recommend such things, the primacy of value is why real(kind=33)
can be used consistently throughout a program. So, if you want to declare two objects to be the same kind, you just have to use expressions which evaluate the same:
real(kind=33) x1, f1
real(kind=selected_real_kind(15)) x2, f2
x1=f1()
x2=f2()
end
function f1()
real(kind=33) f1
f1=1
end function f1
function f2()
real(kind=selected_real_kind(15)) f2
f2=2
end function
Above are shown two styles of specification expressions: using a literal constant (33
) and appropriately referencing an intrinsic function (selected_real_kind(15)
). But specification expressions can also use objects accessible in the scope. We have several techniques for "sharing" objects between scopes, and we can use these techniques in our specification expressions.
Indeed, the declarations in
function vector_norm(n,vec) result(norm)
integer, intent(in) :: n
real(dp), intent(in) :: vec(n)
show one such way with name association! The dummy argument n
is used in the specification of vec
's array bound. This n
is argument associated with the actual argument 9
of the main program: we've used a value in the main program to tell the function something about one of its arguments.
Alas, argument association isn't a form of name association which is useful for kind type parameters, because kind type parameters must be constant (which dummy arguments aren't). We can use a dummy argument to tell us the length of a character object or size of an array, but not the character's kind.
We can use other forms of name association to share constants between one scope (such as main program) and another (a function).
We can use host association or use association. I won't recreate code examples from each of those answers, but hopefully this answer motivates why those two approaches work. Neither approach is necessarily better than the other, but once you understand what they aim to do with regards to scope you can compare suitability on other aspects.
Note that the function vector_norm
of the first linked answer is itself using both use and host association for the kind parameter (and argument association for the array bound).
Upvotes: 1
Reputation: 2981
It is convenient to have a separate module defining precision, and then to import this module throughout the code to ensure that precision is used consistently. With a module structure, your code would become
module precision_module
implicit none
integer, parameter :: dp=selected_real_kind(15)
end module
module vector_norm_module
use precision_module, only : dp
implicit none
contains
function vector_norm(n,vec) result(norm)
integer, intent(in) :: n
real(dp), intent(in) :: vec(n)
real(dp) :: norm
norm = sqrt(sum(vec**2))
end function vector_norm
end module
program main
use precision_module, only : dp
use vector_norm_module, only : vector_norm
implicit none
real(dp) :: v(9)
v(:) = 3.14_dp
print *, 'Vector norm = ', vector_norm(9,v)
end program main
Upvotes: 3