Parameter precision in fortran - fortran

I am using intel fortran 2016. I have defined some precision variables as follows:
! definition of single, double and quad precision
integer, parameter :: SINGLE_PRECISION = selected_real_kind(6, 37)
integer, parameter :: DOUBLE_PRECISION = selected_real_kind(15, 307) ! is used as standard precision
integer, parameter :: QUAD_PRECISION = selected_real_kind(33, 4931)
! definition of variable precision for REAL, INTEGER
integer, parameter :: REAL_TYPE = DOUBLE_PRECISION
integer, parameter :: INTEGER_TYPE = 4
I would like to now use these to control the precision of a parameter that gets declared in a subroutine as follows:
SUBROUTINE SKIP(IUNIT,NBYTS)
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
Character c*1
Parameter(n1 = 1024, nT1 = 8*n1)
I tried the following :
Parameter(INTEGER_TYPE)((n1 = 1024, nT1 = 8*n1)
Parameter(INTEGER_TYPE)((n1 = 1024, nT1 = 8*n1, kind = INTEGER_TYPE)
All to no avail. What is the proper way to define parameter precision in Fortran?
Thanks

Note: this is essentially the same as Francescalus' answer, but with some extra fluf.
The issue at hand here is related to the IMPLICIT statement.
The Fortran standard makes the following statements :
5.5 IMPLICIT statement
In a scoping unit, an IMPLICIT statement specifies a type, and
possibly type parameters, for all implicitly typed data entities whose
names begin with one of the letters specified in the statement.
Alternatively, it may indicate that no implicit typing rules are to
apply in a particular scoping unit.
<snip>
In each scoping unit, there is a mapping, which may be null, between
each of the letters A, B, ..., Z and a type (and type parameters).
An IMPLICIT statement specifies the mapping for the letters in its
letter-spec-list. IMPLICIT NONE specifies the null mapping for all
the letters. If a mapping is not specified for a letter, the
default for a program unit or an interface body is default integer if
the letter is I, J, ..., or N and default real otherwise, and the
default for an internal or module procedure is the mapping in the host
scoping unit.
So in short, by default everything is of type default REAL unless it starts with I,J,...,N, then it is of type default INTEGER.
In the example in the question, the variables n1 and nT1 are hence default INTEGER unless specified otherwise. Thus the following might be a solution :
subroutine skip(IUNIT,NBYTS)
implicit double precision (A-H,O-Z)
character c*1
integer(kind=integer_kind), parameter :: n1 = 1024, nT1 = 8*n1
...
end subroutine skip
As a general remark on variable declaration I would like to make the following remarks:
use implicit none as default. It makes debugging easier
avoid star notation, it is not part of the standard for anything but characters, and for characters it is declared obsolescent.
make use of kind parameters declared in the intrinsic module iso_fortran_env
be aware that double precision does not necessarily mean "double precision" in the literal or IEEE sense of the word. It just means, twice the storage of a real and a higher precision than real. (a higher precision could be one-digit).

You can define a parameter of a specific kind with
TYPE, PARAMETER :: name = value_kind
So to define, say, an integer n1 with kind INTEGER_TYPE you do
integer(kind=INTEGER_TYPE), parameter :: n1 = 1024_INTEGER_TYPE

You have an answer which gives the best way to specify the kind of a named constant. You can find much more detail around this question.
However, I'll add some detail about the parameter statement.
The parameter statement makes an object a named constant and specifies its value. It doesn't specify the type or kind of that object.
The example of the question uses implicit typing for n1 and nT1. These are implicitly default integer.
The implicit rule may be changed (I won't show how), but the type may also be given explicitly:
integer(INTEGER_TYPE) n1, nT1
parameter (n1=1024, nT1=8*n1)
Still, the form of the other answer is preferable. And, as noted there, the kind of the literal constants may also be given in the parameter statement if desired.

Related

Can a Fortran function return multiple variables?

In the example function below how can one tell whether a, b or c are input or output values, other than from the context?
Also, if example() is called is a value assigned to c outside the scope of example()?
function example(a, b, c)
real*8 a, b, c
c = a + b
example = c
end function example
Fortran has the possibility to specify intent attribute:
The INTENT attribute specifies the intended use of a dummy argument. An INTENT (IN) dummy argument is suitable for receiving data from the invoking scoping unit, an INTENT (OUT) dummy argument is suitable for returning data to the invoking scoping unit, and an INTENT (INOUT) dummy argument is suitable for use both to receive data from and to return data to the invoking scoping unit.
Furthermore one can specify a result attribute or give the function a type,
So one could write:
double precision function example(a, b, c)
implicit none
double precision, intent(in) :: a, b
double precision, intent(out) :: c
c = a + b
example = c
end function example
or
function example(a, b, c) result(res)
implicit none
double precision, intent(in) :: a, b
double precision, intent(out) :: c
double precision :: res
c = a + b
res = c
end function example
Note: I also added the "implicit none" and replaced the real*8 by double precision.
You have an answer which talks about intents for arguments. These provide valuable hints to the programmer (as a form of documentation) and compiler as to how the arguments are used. These intents give an idea of the restrictions on an argument and apply to procedures (subroutines as well as functions) more widely.
However, some dummy arguments may even not be allowed to be given an intent. Further, an intent specification doesn't mean that the argument is used in that way (intent(in) arguments needn't be referenced; intent(inout) variables needn't be modified; intent(out) arguments needn't be defined).
Ultimately you will have to look at the function's behaviour.
Given the function of the question
function example(a, b, c)
real*8 a, b, c
c = a + b
example = c
end function example
we can consider a and b to be "inputs" and they must be defined when the function is entered and their values are used in evaluating the function result. The function result is called example but there is a side-effect of modifying c, an "output". Its value on entering the function isn't needed, and it needn't even be defined.
Now, this being Fortran, there is a subtlety to note. You ask
is a value assigned to c outside the scope of example?
and the answer is, possibly.
If example were a subroutine then yes, the actual argument matching c would have a value defined after the subroutine call. With example a function, then maybe not.
Consider:
implicit none
real*8 a, b, c, d
real*8 example ! Really you should be using an explicit interface
a = 1.
b = 2.
c = 0.
d = 0.
print*, example(a,b,c)
print*, c
if (.false..and.example(a,b,d)>0) print*
end program
then although the value of c is modified by this function reference, the variable d actually becomes undefined!1
1 By "undefined" I mean that it doesn't have a value that you can reliably query or use. Because Fortran allows a compiler to short-circuit the evaluation of the function but doesn't it require it, it says that the value becomes undefined. You can't rely on side effects from a function if you can't be sure that the function is used.

Fortran, best use of DIMENSION when initializing array with PARAMETER attribute

In Fortran, are these two methods for initializing a parameter array identical? If not, what is the meaning of dimension(*)?
integer, parameter, dimension(2) :: x = [1,2]
vs
integer, parameter, dimension(*) :: x = [1,2]
The effect of both declarations is the same: a rank-1 named constant array of shape [2] with the obvious values.
Using dimension(*) makes the array implied shape rather than explicit shape: the named constant is of shape implied by the constant expression.
Which is better? Well, implied shape is not supported by all compilers (being a Fortran 2008 feature), but it saves worrying about writing shape twice.

Parametrized derived types with kind parameter as subroutine argument

Say we have the following code:
module foo
use :: iso_fortran_env
implicit none
type :: bar (p, q)
integer, kind :: p
integer, len :: q
integer(kind = p), dimension(q) :: x
end type bar
contains
subroutine barsub (this)
class(bar(*,*)), intent(in) :: this
write (*,*) this%x
end subroutine barsub
end module foo
This code does not compile with either gfortran 8 or pgfort 18.4. The pgi compiler says
Illegal selector - KIND value must be non-negative
Assumed type parameter (*) cannot be used with non-length type parameter p
whereas gfortran yields
The KIND parameter 'p' at (1) cannot either be ASSUMED or DEFERRED
If I change above code to
subroutine barsub (this)
class(bar(INT32,*)), intent(in) :: this
write (*,*) this%x
end subroutine barsub
it compiles fine with both compilers.
Is it possible to write a subroutine where the kind parameter does not need to be specified explicitly? In the example above, the code would be the same for INT32, INT64, ... and I don't want to copy paste it for every imaginable value of the kind parameter. It works fine for the len parameter. Why can't I do the same with the kind parameter?
Is it possible to write a subroutine where the kind parameter does not need to be specified explicitly?
No, kind type parameters need to be given by a constant expression or defaulted, see, e.g., the Fortran 2008 standard, definition 1.3.147.12.3.
Why can't I do the same with the kind parameter?
The fact that len and kind type parameters have different uses and requirements is the point of having two types of type parameters, if their characteristics were the same we wouldn't need two of them.
Note that procedures require of the kind parameters of their dummy arguments of parameterized derived types just same they require of the kinds of their dummy arguments of intrinsic types: to have their values defined at compilation time.

Passing parameters to a subroutine in Fortran

I'm trying to understand how to pass some variables with values, to a subroutine, from another subroutine.
I have the code:
program pg
call sub()
end
subroutine sub()
character :: P(12,12)
character :: D(20), N(26), userInput
integer :: A,B
A = 5
B = 2
userInput = "hello"
call test(P,D,N,userInput,A,B)
end subroutine
subroutine test(P,D,N,userInput,A,B)
end subroutine test
But that gives me a warning of:
Warning: Type mismatch in argument 'p' at (1); passed CHARACTER(1) to REAL(4)
I'm not exactly sure on how to get rid of this warning, let alone if the subroutine call is correct (syntax wise). Any help would be much appreciated.
First, why this error is happening: You have not explicitly declared any variables in subroutine test so by default, the IMPLICIT variable type rules are applied - variables starting with [A-H,O-Z] are treated as single-precision reals (REAL(4)) and the remainder (starting with [I-N]) are integers. In this case, the real arguments to test are P, D, userInput, A, and B; N is treated as an integer. Also these are all treated as scalar quantities since no dimension information is provided in test.
In subroutine sub, the variable P is declared as a 12-by-12 array of length-1 strings (single characters or CHARACTER(1)). This explains why you're getting the type mismatch error.
Advice: Read up on the IMPLICIT statement and start your code with IMPLICIT NONE, always. This forces you to declare all your variables. This slight inconvenience allows the compiler to catch typos and namespace collisions and is considered best practice. It won't solve your next problem (P, D, and N are arrays passed in as arguments to a routine which expects them to be scalars) but it will get rid of the type mismatch error.
For bonus points, look into the INTENT attribute for argument declarations. If you know that certain arguments are read-only or will only have their values set within a routine, you can declare them as INTENT(IN) or INTENT(OUT). This is an added guard against accidentally changing read-only variables or reading variables before they've been initialized.

No lifting of scalar arguments to arrays in Fortran

Why is it that Fortran will promote a scalar expression to an array, in an expression, but not as an argument to a procedure? In particular, why did the standards body make this design decision? Is it solely because of ambiguity, should the procedure be overloaded? Could an error message in that situation be an alternative approach?
For example, In the code below, the last statement, x = foo(7), produces the GFortran error: Error: Rank mismatch in argument 'a' at (1) (1 and 0).
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a+1
end function foo
end module m
program p
use m
integer, dimension(4) :: x
integer, parameter, dimension(4) :: y = (/1,2,3,4/)
x = 7
x = foo(x)
x = foo(y)
x = foo(x + 7)
x = foo(7)
end program p
This question should have asked about why an array assignment will promote a scalar value source to an array target; unlike an array function. I expect that's simply a convenient special case though. Any comments gratefully received in the begging caps below.
If you want the function to handle scaler and array arguments, declare it as "elemental" and with scaler dummy arguments. Then it will be able to handle both scaler and array actual arguments, including scaler expressions. Will that meet your need?
The change:
elemental function foo(a) result(b)
integer, intent (in) :: a
integer :: b
b = a+1
end function foo
Perhaps they provided a way to do what you want, and one way was enough?
Procedure calling in Fortran with explicit interfaces (which you get automatically when using module procedures) requires a TKR (type, kind, rank) match. As an array is a different type than a scalar, not to mention the rank mismatch, this is not allowed.
Is it because of ambiguity should the procedure be overloaded?
That would be a problem, yes.
Could an error message in that situation be an alternative approach?
Could pink unicorns exist? Maybe, but to the best of my knowledge they don't. IOW, the Fortran standard currently requires TKR matching, and thus a standard conforming compiler must enforce this requirement. If you want to change that, I recommend making a proposal to the standards committee.
I would think the answer to this is pretty clear. Let's slightly modify your example:
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a+1
a(2) = -777 ! new line; modify one element
end function foo
end module m
program p
use m
integer :: x
integer, dimension(4) :: y
x = 7
y = foo(x) ! pass a scalar
end program p
what is x supposed to be after the call to foo?
Now, sure, you could have the semantics of argument passing change depending on whether or not it's an intent(in) variable, but that is not something which is going to clarify things for programmers.
If the function call is supposed to 'distribute' somehow over array elements, then as MSB points out, elemental is the way to go. Otherwise, one just makes sure one's arguments match one's parameters.