Fortran 90 Commands
Fortran 90 Commands
Fortran 90 Commands
2. Numerical functions
3. Mathematical functions
6. Kind functions
7. Logical function
o Time routines
Introduction
There is a large a number of intrinsic functions and five intrinsic subroutinesin Fortran
90. I treat the numeric and mathematical routines very shortly, since they are not
changed from Fortran 77 and therefore should be well-known.
This section is based on section 13 of the ISO standard (1991), which contains a more
formal treatment. We follow the arrangement of the different functions and
subroutines in the standard, but explain directly in the list. For a more detailed
treatment we refer to Metcalf and Reid (1990, 1993).
We have not always given all the natural limitations to the variables, for example that
the rank is not permitted to be negative.
In addition, CEILING, FLOOR and MODULO have been added to Fortran 90. Only the last
one is difficult to explain, which is most easily done with the examples from ISO
(1991)
MOD (8,5) gives 3 MODULO (8,5) gives 3
MOD (-8,5) gives -3 MODULO (-8,5) gives 2
MOD (8,-5) gives 3 MODULO (8,-5) gives -2
MOD (-8,-5) gives -3 MODULO (-8,-5) gives -3
The following functions from Fortran 77 can use a kind-parameter like in AINT(A,
kind), namely AINT, ANINT, CMPLX, INT, NINT and REAL.
A historic fact is that the numerical functions in Fortran 66 had to have specific
(different) names in different precisions, and these explicit names are still the only
ones which can be used when a function name is passed as an argument.
A complete table of all the numerical functions follow. Those names that are indicated
with a star * are not permitted to be used as arguments. Some functions,
like INT and IFIX have two specific names, either can be used. On the other hand,
some functions do not have any specific name. Below I use C for complex floating
point values, D for floating point values in double precision, I for integers, and R for
floating point values in single precision.
Conversion INT - I I
to integer * INT R I
* IFIX R I
* IDINT D I
(of the real part) - C I
Conversion DBLE - I D
to double - R D
precision - D D
(real part) - C D
Conversion CMPLX - I (2I) C
to complex - R (2R) C
- D (2D) C
- C C
Floor FLOOR - I I
- R R
- D D
Ceiling CEILING - I I
- R R
- D D
The function CMPLX can have one or two arguments, if two arguments are present
these must be of the same type but not COMPLEX.
The sign transfer function SIGN(X,Y) takes the sign of the second argument and puts it
on the first argument, ABS(X) if Y >= 0 and -ABS(X) if Y < 0.
Positive difference DIM is a function I have never used, but DIM(X,Y) gives X-Y if this
is positive and zero in the other case.
Inner product DPROD on the other hand is a very useful function which gives the
product of two numbers in single precision as a double precision number. It is both
fast and accurate.
The two functions MAX and MIN are unique in that they may have an arbitrary number
of arguments, but at least two. The arguments have to be of the same type, but are not
permitted to be of type COMPLEX.
3. Mathematical functions:
Same as in Fortran 77. All trigonometric functions work in radians. The following are
available: ACOS, ASIN, ATAN, ATAN2, COS, COSH, EXP, LOG, LOG10, SIN, SINH,
SQRT, TAN and TANH.
A historic fact is that the mathematical functions in Fortran 66 had to have specific
(different) names in different precisions, and these explicit names are still the only
ones which can be used when a function name is passed as an argument.
A complete table of all the mathematical functions follow. Below I use C for complex
floating point values, D for floating point values in double precision, I for integers,
and R for floating point values in single precision.
The square root gives a real result for a real argument in single or double precision,
and a complex result for a complex argument. So SQRT(-1.0) gives an error message
(usually already at compile time), while you can get the complex square root using the
following statements.
COMPLEX, PARAMETER :: MINUS_ONE = -1.0
COMPLEX :: Z
Z = SQRT(MINUS_ONE)
The argument for the usual logarithms has to be positive, while the argument
for CLOG must be different from zero.
The modulus for the argument to ASIN and ACOS has to be at most 1. The result will be
within [-pi/2, pi/2] and [0, pi], respectively.
The function ATAN2(Y,X) = arctan(y,x) will return a value in (-pi, pi]. If Y is positive
the result will be positive. If Y is zero the result will be zero if X is positive, and pi
if X is negative. If Y is negative the result will be negative. If X is zero the result will
be plus or minus pi/2. Both X and Y are not permitted to be zero simultaneously. The
purpose of the function is to avoid division by zero.
A natural limitation for the mathematical functions is the limited accuracy and range,
which means that for example EXP can cause underflow or overflow at rather common
values of the argument. The trigonometric functions will get very low accuracy for
large arguments. These limitations are implementation dependent, and should be given
in the vendor's manual.
LGE(STRING_A, STRING_B)
LGT(STRING-A, STRING_B)
LLE(STRING_A, STRING_B)
LLT(STRING_A, STRING_B)
The above routines compare two strings using sorting according to ASCII. If a string
is shorter than the other, blanks are added at the end of the short string. If a string
contains a character outside the ASCII character set, the result is implementation-
dependent.
REPEAT(STRING, NCOPIES) Concatenates a character string NCOPIES
times with itself.
SCAN(STRING, SET, back) Returns the position of the first occurrence
of any character in the string SET in the string
STRING. If BACK is true, you will get
the rightmost such character.
TRIM(STRING) Returns the character string STRING without
trailing blanks.
VERIFY(STRING, SET, back) Returns the position of the first character
in STRING which is not in SET. If BACK
is TRUE, you get the last one!
The result is zero if all characters are
included!
6. Kind functions:
KIND(X)
SELECTED_INT_KIND(R)
SELECTED_REAL_KIND(p, r)
The first returns the kind of the actual argument, which can be of the type INTEGER,
REAL, COMPLEX, LOGICAL or CHARACTER. The argument X does not have to be assigned
any value. The second returns an integer kind with the requested number of digits, and
the third returns the kind for floating-point numbers with numerical precision at
least P digits and one decimal exponent range between -R and +R. The
parameters P and R must be scalar integers. At least one of P and R must be given.
The result of SELECTED_INT_KIND is an integer from zero and upward, if the desired
kind is not available you will get -1. If several implemented types satisfy the
condition, the one with the least decimal range is used. If there still are several types
or kinds that satisfy the condition, the one with the smallest kind number will be used.
The result of SELECTED_REAL_KIND is also an integer from zero and upward; if the
desired kind is not available, then -1 is returned if the precision is not available, -2 if
the exponent range is not available and -3 if no one of the requirements are available.
If several implemented types satisfy the condition, the one with the least decimal
precision is returned, and if there are several of them, the one with the least kind
number is returned.
Examples are given in chapter 2 of the main text. Examples of kinds in a few different
implementations (NAG and Cray) are given in Appendix 6.
7. Logical function:
LOGICAL(L, kind) converts between different kinds of logical variables. Logical
variables can be implemented in various ways, for example with a physical
representation occupying one bit (not recommended), one byte, one word or perhaps
even one double word. This difference is important if COMMON and EQUIVALENCE with
logical variables have been misused in a program in the traditional way of Fortran 66
programming.
MATMUL(MATRIX_A, MATRIX_B) makes the matrix product of two matrices, which must
be consistent, i.e. have the dimensions like (M, K) and (K, N). Used in chapter 11 of
the main text.
ANY(MASK, dim) returns a logical value that indicates whether any relation
in MASK is .TRUE., along only the desired dimension if the second argument is given.
MAXVAL(ARRAY, dim, mask) returns the largest value in the array ARRAY, of those that
obey the relation in the third argument MASK if that one is given, along only the desired
dimension if the second argumentDIM is given.
MINVAL(ARRAY, dim, mask) returns the smallest value in the array ARRAY, of those that
obey the relation in the third argument MASK if that one is given, along only the desired
dimension if the second argumentDIM is given.
PRODUCT(ARRAY, dim, mask) returns the product of all the elements in the array ARRAY,
of those that obey the relation in the third argument MASK if that one is given, along
only the desired dimension if the second argument DIM is given.
SUM (ARRAY, dim, mask) returns the sum of all the elements in the array ARRAY, of
those that obey the relation in the third argument MASK if that one is given, along only
the desired dimension if the second argument DIM is given. An example is given
in Appendix 3, section 10.
LBOUND(ARRAY, dim) is a function which returns the lower dimension limit for
the ARRAY. If DIM (the dimension) is not given as an argument, you get an integer
vector, if DIM is included, you get the integer value with exactly that lower dimension
limit, for which you asked.
I here give a rather complete example of the use of MERGE which also
uses RESHAPE from the next section in order to build suitable test matrices.
Note that the two subroutines WRITE_ARRAY and WRITE_L_ARRAY are test routines to
write matrices which in the first case are of a REAL type, in the second case of
a LOGICAL type.
IMPLICIT NONE
INTERFACE
SUBROUTINE WRITE_ARRAY (A)
REAL :: A(:,:)
END SUBROUTINE WRITE_ARRAY
SUBROUTINE WRITE_L_ARRAY (A)
LOGICAL :: A(:,:)
END SUBROUTINE WRITE_L_ARRAY
END INTERFACE
T F F
F T F
The result is a vector with as many elements as those in ARRAY that obey the
conditions if VECTOR is not included (i.e. all elements if MASK is a scalar with
value .TRUE.). In the other case the number of elements of the result will be as many
as in VECTOR. The values will be the approved ones, i.e. the values which fulfill the
condition, and will be in the ordinary Fortran order. If VECTOR is included and the
number of its elements exceeds the number of approved values, the lacking values
required for the result are taken from the corresponding locations in VECTOR.
The following example is based on the modification of the one for MERGE , but I give
now only the results.
ARRAY
11.0000000 12.0000000 13.0000000
21.0000000 22.0000000 23.0000000
VECTOR
-11.0000000
-21.0000000
-12.0000000
-22.0000000
-13.0000000
-23.0000000
MASK
T F F
F T F
PACK(ARRAY, MASK)
11.0000000
22.0000000
UNPACK(VECTOR, MASK, ARRAY) scatters a vector to an array under control of MASK. The
shape of the logical array MASK has to agree with the one for ARRAY. The
array VECTOR has to have the rank 1 (i.e. it is a vector) with at least as many elements
as those that are true in MASK, and also has to have the same type as ARRAY. If ARRAY is
given as a scalar then it is considered to be an array with the same shape as MASKand
the same scalar elements everywhere.
The result will be an array with the same shape as MASK and the same type as VECTOR.
The values will be those from VECTOR that are accepted (i.e. those fulfilling the
condition in MASK), taken in the ordinary Fortran order, while in the remaining
positions in ARRAY the old values are kept.
The result has of course a shape SHAPE and the elements are those in SOURCE, possibly
complemented with PAD. The different dimensions have been permuted at the
assignment of the elements if ORDER was included, but without influencing the shape
of the result.
A few simple examples are given in the previous and the next section and also
in Appendix 3, section 9. A more complicated example, illustrating also the optional
arguments, follows.
! PROGRAM TO TEST THE OPTIONAL ARGUMENTS TO RESHAPE
INTERFACE
SUBROUTINE WRITE_MATRIX(A)
REAL, DIMENSION(:,:) :: A
END SUBROUTINE WRITE_MATRIX
END INTERFACE
REAL, DIMENSION (1:9) :: B = (/ 11, 12, 13, 14, 15, 16, 17, 18, 19 /)
REAL, DIMENSION (1:3, 1:3) :: C, D, E
REAL, DIMENSION (1:4, 1:4) :: F, G, H
C = RESHAPE( B, (/ 3, 3 /) )
CALL WRITE_MATRIX(C)
END
SUBROUTINE WRITE_MATRIX(A)
REAL, DIMENSION(:,:) :: A
WRITE(*,*)
DO I = LBOUND(A,1), UBOUND(A,1)
WRITE(*,*) (A(I,J), J = LBOUND(A,2), UBOUND(A,2))
END DO
END SUBROUTINE WRITE_MATRIX
The output from the above program is as follows.
11.0000000 14.0000000 17.0000000
12.0000000 15.0000000 18.0000000
13.0000000 16.0000000 19.0000000
EOSHIFT(ARRAY, SHIFT, boundary, dim) performs shift to the left if SHIFT is positive
and to the right if it is negative. Instead of the elements shifted out new elements are
taken from BOUNDARY. If ARRAY is a vector the shift is being done in a natural way, if it
is an array of a higher rank, the shift on all sections is along the dimension DIM.
If DIM is missing, it is considered to be 1, in other cases it has to have a scalar integer
value between 1 and n (where n equals the rank of ARRAY). The argument SHIFT is a
scalar integer if ARRAY has rank 1, in the other case it can be a scalar integer or an
integer array of rank n-1 and with the same shape as the array ARRAY except along the
dimension DIM (which is removed because of the lower rank).
The corresponding applies to BOUNDARY which has to have the same type as the ARRAY.
If the parameter BOUNDARY is missing you have the choice of values zero, .FALSE. or
blank being used, depending on the data type. Different sections can thus be shifted in
various directions and with various numbers of positions. A simple example of the
above two functions for the vector case follows, both the program and the output.
REAL, DIMENSION(1:6) :: A = (/ 11.0, 12.0, 13.0, 14.0, &
15.0, 16.0 /)
REAL, DIMENSION(1:6) :: X, Y
WRITE(*,10) A
X = CSHIFT ( A, SHIFT = 2)
WRITE(*,10) X
Y = CSHIFT (A, SHIFT = -2)
WRITE(*,10) Y
X = EOSHIFT ( A, SHIFT = 2)
WRITE(*,10) X
Y = EOSHIFT ( A, SHIFT = -2)
WRITE(*,10) Y
10 FORMAT(1X,6F6.1)
END
MINLOC(ARRAY, mask) returns the position of the smallest element in the array ARRAY ,
if MASK is included only for those which fulfill the conditions in MASK. The result is an
integer vector!
A subroutine which returns the date, the time and the time zone. At least one
argument has to be given.
DATE must be a scalar character string variable with at least 8 characters and it
is assigned the value CCYYMMDD for century, year, month and day. All are given
numerically, with blanks if the system does not include the date.
TIME must also be a scalar character string variable with at least 10 characters
and it is assigned a value hhmmss.sss for time in hours, minutes, seconds and
milliseconds. All are given numerically with blanks if the system does not
include a clock.
ZONE must be a scalar character string variable with at least 5 characters and it
is assigned the value +hhmm for sign, time in hours and minutes for the local
time difference with UTC (which was previously called Greenwich Mean
Time). All are given numerically, with blanks if the system does not include a
clock. In Sweden we therefore get +0100 in winter and +0200 in summer, in
Novosibirsk we get +0700 .
Subroutine which returns the system time. At least one argument has to be
given. COUNT is a scalar integer which is increased by one for each cycle up
to COUNT_MAX , where it starts once again. If there is no system clock then -
HUGE(0) is returned.
COUNT_RATE is a scalar integer that gives the number of cycles per second. If
there is no system clock the value zero is returned.
COUNT_MAX is a scalar integer which gives the maximum value that COUNT can
reach. If there is no system clock, zero is returned instead.
A subroutine which copies the sequence of bits in position FROMPOS and has the
length LEN to target TO starting in position TOPOS. The remaining bits are not
changed. All quantities have to be integers and all except TO have to
have INTENT(IN) while TO is supposed to have INTENT(INOUT) and be of the
same kind type as FROM. The same variable can be both FROM and TO. Some
natural restrictions apply to the values of LEN, FROMPOS and TOPOS and you also
have to consider the value of BIT_SIZE.
This subroutine returns in the floating-point number variable HARVEST one (or
several if HARVEST is an array) random numbers between zero and 1.
RANDOM_SEED(size, put, get)