ⓘ Fortran 95 language features. This is an overview of Fortran 95 language features. Included are the additional features of TR-15581:Enhanced Data Type Facilitie ..

                                     

ⓘ Fortran 95 language features

This is an overview of Fortran 95 language features. Included are the additional features of TR-15581:Enhanced Data Type Facilities, which have been universally implemented. Old features that have been superseded by new ones are not described – few of those historic features are used in modern programs although most have been retained in the language to maintain backward compatibility. The current standard is Fortran 2018; many of its new features are still being implemented in compilers. The additional features of Fortran 2003, Fortran 2008 and Fortran 2018 are described by Metcalf, Reid and Cohen.

                                     

1. Language elements

Fortran is case-insensitive. The convention of writing Fortran keywords in upper case and all other names in lower case is adopted in this article; except, by way of contrast, in the input/output descriptions Data transfer and Operations on external files.

                                     

1.1. Language elements Data initialization

Variables can be given initial values as specified in a specification statement:

and a default initial value can be given to the component of a derived data type:

When local variables are initialized within a procedure they implicitly acquire the SAVE attribute:

This declaration is equivalent to

for local variables within a subroutine or function. The SAVE attribute causes local variables to retain their value after a procedure call and then to initialize the variable to the saved value upon returning to the procedure.

                                     

1.2. Language elements PARAMETER attribute

A named constant can be specified directly by adding the PARAMETER attribute and the constant values to a type statement:

                                     

1.3. Language elements DATA statement

The DATA statement can be used for scalars and also for arrays and variables of derived type. It is also the only way to initialise just parts of such objects, as well as to initialise to binary, octal or hexadecimal values:

                                     

1.4. Language elements Initialization expressions

The values used in DATA and PARAMETER statements, or with these attributes, are constant expressions that may include references to: array and structure constructors, elemental intrinsic functions with integer or character arguments and results, and the six transformational functions REPEAT, SELECTED_INT_KIND, TRIM, SELECTED_REAL_KIND, RESHAPE and TRANSFER see Intrinsic procedures:

                                     

1.5. Language elements Specification expressions

It is possible to specify details of variables using any non-constant, scalar, integer expression that may also include inquiry function references:



                                     

2.1. Expressions and assignments Scalar numeric

The usual arithmetic operators are available – +, -, *, ** given here in increasing order of precedence.

Parentheses are used to indicate the order of evaluation where necessary:

The rules for scalar numeric expressions and assignments accommodate the non-default kinds. Thus, the mixed-mode numeric expression and assignment rules incorporate different kind type parameters in an expected way:

converts integer0 to a real value of the same kind as real1 ; the result is of same kind, and is converted to the kind of real2 for assignment.

These functions are available for controlled rounding of real numbers to integers:

  • NINT: round to nearest integer, return integer result
  • CEILING: smallest integral value not less than argument round up Fortran-90
  • INT: truncate round towards zero, return integer result
  • ANINT: round to nearest integer, return real result
  • AINT: truncate round towards zero, return real result
  • FLOOR: largest integral value not greater than argument round down Fortran-90


                                     

2.2. Expressions and assignments Scalar characters

In the case of scalar characters and given CHARACTER 8 result

it is legal to write

Concatenation is performed by the operator //.

                                     

2.3. Expressions and assignments Derived-data types

No built-in operations except assignment, defined on component-by component basis exist between derived data types mutually or with intrinsic types. The meaning of existing or user-specified operators can be redefined though:

we can write

Notice the "overloaded" use of the intrinsic symbol // and the named operator.concat. A difference between the two cases is that, for an intrinsic operator token, the usual precedence rules apply, whereas for named operators, precedence is the highest as a unary operator or the lowest as a binary one. In

the two expressions are equivalent only if appropriate parentheses are added as shown. In each case there must be defined, in a module, procedures defining the operator and assignment, and corresponding operator-procedure association, as follows:

The string concatenation function is a more elaborated version of that shown already in Basics. Note that in order to handle the error condition that arises when the two strings together exceed the preset 80-character limit, it would be safer to use a subroutine to perform the concatenation in this case operator-overloading would not be applicable.

Defined operators such as these are required for the expressions that are allowed also in structure constructors see Derived-data types:



                                     

2.4. Expressions and assignments Arrays

In the case of arrays then, as long as they are of the same shape conformable, operations and assignments are extended in an obvious way, on an element-by-element basis. For example, given declarations of

it can be written:

The order of expression evaluation is not specified in order to allow for optimization on parallel and vector machines. Of course, any operators for arrays of derived type must be defined.

Some real intrinsic functions that are useful for numeric computations are

These are array valued for array arguments elemental, like all FORTRAN 77 functions except LEN:

the last seven are for characters.

                                     

3.1. Control statements Branching and conditions

The simple GO TO label exists, but is usually avoided – in most cases, a more specific branching construct will accomplish the same logic with more clarity.

The simple conditional test is the IF statement: IF a > b x = y

A full-blown IF construct is illustrated by

                                     

3.2. Control statements CASE construct

The CASE construct is a replacement for the computed GOTO, but is better structured and does not require the use of statement labels:

Each CASE selector list may contain a list and/or range of integers, character or logical constants, whose values may not overlap within or between selectors:

A default is available:

There is only one evaluation, and only one match.



                                     

3.3. Control statements DO construct

A simplified but sufficient form of the DO construct is illustrated by

where we note that loops may be optionally named so that any EXIT or CYCLE statement may specify which loop is meant.

Many, but not all, simple loops can be replaced by array expressions and assignments, or by new intrinsic functions. For instance

becomes simply tot = SUM a m: n)

                                     

4.1. Program units and procedures Definitions

In order to discuss this topic we need some definitions. In logical terms, an executable program consists of one main program and zero or more subprograms or procedures - these do something. Subprograms are either functions or subroutines, which are either external, internal or module subroutines. External subroutines are what we knew from FORTRAN 77.

From an organizational point of view, however, a complete program consists of program units. These are either main programs, external subprograms or modules and can be separately compiled.

An example of a main and complete program is

An example of a main program and an external subprogram, forming an executable program, is

The form of a function is

The form of reference of a function is x = name a, b

                                     

4.2. Program units and procedures Internal procedures

An internal subprogram is one contained in another at a maximum of one level of nesting and provides a replacement for the statement function:

We say that outer is the host of inner, and that inner obtains access to entities in outer by host association e.g. to x, whereas y is a local variable to inner.

The scope of a named entity is a scoping unit, here outer less inner, and inner.

The names of program units and external procedures are global, and the names of implied-DO variables have a scope of the statement that contains them.

                                     

4.3. Program units and procedures Modules

Modules are used to package

  • interface blocks another scoping unit, see Interface blocks;
  • subprograms which among other things replaces the use of ENTRY from Fortran 77;
  • type definitions themselves a scoping unit;
  • global data replaces COMMON and BLOCK DATA from Fortran 77;
  • namelist groups see any textbook.

An example of a module containing a type definition, interface block and function subprogram is

and the simple statement

provides use association to all the modules entities. Module subprograms may, in turn, contain internal subprograms.

                                     

4.4. Program units and procedures Controlling accessibility

The PUBLIC and PRIVATE attributes are used in specifications in modules to limit the scope of entities. The attribute form is

and the statement form is

The statement form has to be used to limit access to operators, and can also be used to change the overall default:

For derived types there are three possibilities: the type and its components are all PUBLIC, the type is PUBLIC and its components PRIVATE the type only is visible and one can change its details easily, or all of it is PRIVATE for internal use in the module only:

The USE statements purpose is to gain access to entities in a module. It has options to resolve name clashes if an imported name is the same as a local one:

or to restrict the used entities to a specified set:

These may be combined:

                                     

4.5. Program units and procedures Arguments

We may specify the intent of dummy arguments:

Also, INOUT is possible: here the actual argument must be a variable unlike the default case where it may be a constant.

Arguments may be optional:

allows us to call mincon by

Arguments may be keyword rather than positional which come first:

Optional and keyword arguments are handled by explicit interfaces, that is with internal or module procedures or with interface blocks.

                                     

4.6. Program units and procedures Interface blocks

Any reference to an internal or module subprogram is through an interface that is explicit that is, the compiler can see all the details. A reference to an external or dummy procedure is usually implicit the compiler assumes the details. However, we can provide an explicit interface in this case too. It is a copy of the header, specifications and END statement of the procedure concerned, either placed in a module or inserted directly:

An explicit interface is obligatory for

  • optional and keyword arguments;
  • POINTER function result;
  • POINTER and TARGET arguments see Pointers;
  • new-style array arguments and array functions Array handling.

It allows full checks at compile time between actual and dummy arguments.

In general, the best way to ensure that a procedure interface is explicit is either to place the procedure concerned in a module or to use it as an internal procedure.



                                     

4.7. Program units and procedures Overloading and generic interfaces

Interface blocks provide the mechanism by which we are able to define generic names for specific procedures:

where a given set of specific names corresponding to a generic name must all be of functions or all of subroutines. If this interface is within a module, then it is simply

We can use existing names, e.g. SIN, and the compiler sorts out the correct association.

We have already seen the use of interface blocks for defined operators and assignment see Modules.

                                     

4.8. Program units and procedures Recursion

Indirect recursion is useful for multi-dimensional integration. For

We might have

and to integrate fx, y over a rectangle:

Direct recursion is when a procedure calls itself, as in

Here, we note the RESULT clause and termination test.

                                     

4.9. Program units and procedures Pure procedures

This is a feature for parallel computing.

In the FORALL statement and construct, any side effects in a function can impede optimization on a parallel processor – the order of execution of the assignments could affect the results. To control this situation, we add the PURE keyword to the SUBROUTINE or FUNCTION statement – an assertion that the procedure expressed simply:

  • performs no I/O,
  • for functions, does not alter any of its arguments.
  • has no saved variables with the SAVE attribute that retains values between invocations, and
  • alters no global variable,

A compiler can check that this is the case, as in

All the intrinsic functions are pure.

                                     

5. Array handling

Array handling is included in Fortran for two main reasons:

  • for the additional optimization opportunities it gives compilers although there are plenty of opportunities for degrading optimization too!.
  • the notational convenience it provides, bringing the code closer to the underlying mathematical form;

At the same time, major extensions of the functionality in this area have been added. We have already met whole arrays above #Arrays 1 and here #Arrays 2 - now we develop the theme.

                                     

5.1. Array handling Zero-sized arrays

A zero-sized array is handled by Fortran as a legitimate object, without special coding by the programmer. Thus, in

no special code is required for the final iteration where i = n. We note that a zero-sized array is regarded as being defined; however, an array of shape 0.2 is not conformable with one of shape 0.3, whereas x 1: 0 = 3 is a valid do nothing statement.

                                     

5.2. Array handling Assumed-shape arrays

These are an extension and replacement for assumed-size arrays. Given an actual argument like:

the corresponding dummy argument specification defines only the type and rank of the array, not its shape. This information has to be made available by an explicit interface, often using an interface block see Interface blocks. Thus we write just

and this is as if da were dimensioned 11.21. However, we can specify any lower bound and the array maps accordingly.

The shape, not bounds, is passed, where the default lower bound is 1 and the default upper bound is the corresponding extent.

                                     

5.3. Array handling Automatic arrays

A partial replacement for the uses to which EQUIVALENCE was put is provided by this facility, useful for local, temporary arrays, as in

The actual storage is typically maintained on a stack.



                                     

5.4. Array handling ALLOCATABLE and ALLOCATE

Fortran provides dynamic allocation of storage; it relies on a heap storage mechanism and replaces another use of EQUIVALENCE. An example for establishing a work array for a whole program is

The work array can be propagated through the whole program via a USE statement in each program unit. We may specify an explicit lower bound and allocate several entities in one statement. To free dead storage we write, for instance,

Deallocation of arrays is automatic when they go out of scope.

                                     

5.5. Array handling Elemental operations, assignments and procedures

We have already met whole array assignments and operations:

In the second assignment, an intrinsic function returns an array-valued result for an array-valued argument. We can write array-valued functions ourselves they require an explicit interface:

Elemental procedures are specified with scalar dummy arguments that may be called with array actual arguments. In the case of a function, the shape of the result is the shape of the array arguments.

Most intrinsic functions are elemental and Fortran 95 extends this feature to non-intrinsic procedures, thus providing the effect of writing, in Fortran 90, 22 different versions, for ranks 0-0, 0-1, 1-0, 1-1, 0-2, 2-0, 2-2. 7-7, and is further an aid to optimization on parallel processors. An elemental procedure must be pure.

The dummy arguments cannot be used in specification expressions see above except as arguments to certain intrinsic functions.

                                     

5.6. Array handling WHERE

Often, we need to mask an assignment. This we can do using the WHERE, either as a statement:

note: the test is element-by-element, not on whole array, or as a construct:

or

Further:

  • a WHERE assignment statement is permitted to be a defined assignment, provided that it is elemental;
  • WHERE constructs may be nested within one another, just FORALL constructs;
  • a WHERE construct may be named in the same way as other constructs.
  • a WHERE construct may contain any number of masked ELSEWHERE statements but at most one ELSEWHERE statement without a mask, and that must be the final one;
  • it is permitted to mask not only the WHERE statement of the WHERE construct, but also any ELSEWHERE statement that it contains;
                                     

5.7. Array handling The FORALL statement and construct

When a DO construct is executed, each successive iteration is performed in order and one after the other – an impediment to optimization on a parallel processor.

where the individual assignments may be carried out in any order, and even simultaneously. The FORALL may be considered to be an array assignment expressed with the help of indices.

with masking condition.

The FORALL construct allows several assignment statements to be executed in order.

is equivalent to the array assignments

The FORALL version is more readable.

Assignment in a FORALL is like an array assignment: as if all the expressions were evaluated in any order, held in temporary storage, then all the assignments performed in any order. The first statement must fully complete before the second can begin.

A FORALL may be nested, and may include a WHERE. Procedures referenced within a FORALL must be pure.

                                     

5.8. Array handling Array elements

For a simple case, given

we can reference a single element as, for instance, a1, 1. For a derived-data type like

we can declare an array of that type:

and a reference like tar n, 2 is an element a scalar! of type fun_del, but tar n, 2% du is an array of type real, and tar n, 2% du 2 is an element of it. The basic rule to remember is that an array element always has a subscript or subscripts qualifying at least the last name.

                                     

5.9. Array handling Array subobjects sections

The general form of subscript for an array section is

indicates an optional item) as in

Note that a vector subscript with duplicate values cannot appear on the left-hand side of an assignment as it would be ambiguous. Thus,

is illegal. Also, a section with a vector subscript must not be supplied as an actual argument to an OUT or INOUT dummy argument. Arrays of arrays are not allowed:

We note that a given value in an array can be referenced both as an element and as a section:

depending on the circumstances or requirements. By qualifying objects of derived type, we obtain elements or sections depending on the rule stated earlier:

                                     

5.10. Array handling Arrays intrinsic functions

Vector and matrix multiply

DOT_PRODUCT Dot product of 2 rank-one arrays MATMUL Matrix multiplication

Array reduction

ALL True if all values are true ANY True if any value is true. Example: IF ANYa > b) THEN COUNT Number of true elements in array MAXVAL Maximum value in an array MINVAL Minimum value in an array Product of array elements Sum of array elements

Array inquiry

ALLOCATED Array allocation status LBOUND Lower dimension bounds of an array Shape of an array or scalar SIZE Total number of elements in an array UBOUND Upper dimension bounds of an array

Array construction

Merge under mask Pack an array into an array of rank one under a mask SPREAD Replicate array by adding a dimension Unpack an array of rank one into an array under mask

Array reshape

Reshape an array

Array manipulation

CSHIFT Circular shift EOSHIFT End-off shift Transpose of an array of rank two

Array location

MAXLOC Location of first maximum value in an array MINLOC Location of first minimum value in an array
                                     

6.1. Pointers Basics

Pointers are variables with the POINTER attribute; they are not a distinct data type and so no pointer arithmetic is possible.

They are conceptually a descriptor listing the attributes of the objects targets that the pointer may point to, and the address, if any, of a target. They have no associated storage until it is allocated or otherwise associated by pointer assignment, see below:

and they are dereferenced automatically, so no special symbol required. In

the value of the target of var is used and modified. Pointers cannot be transferred via I/O. The statement

writes the value of the target of var and not the pointer descriptor itself.

A pointer can point to another pointer, and hence to its target, or to a static object that has the TARGET attribute:

but they are strongly typed:

and, similarly, for arrays the ranks as well as the type must agree.

A pointer can be a component of a derived type:

and we can define the beginning of a linked chain of such entries:

After suitable allocations and definitions, the first two entries could be addressed as

but we would normally define additional pointers to point at, for instance, the first and current entries in the list.

                                     

6.2. Pointers Association

A pointers association status is one of

Some care has to be taken not to leave a pointer dangling by use of DEALLOCATE on its target without nullifying any other pointer referring to it.

The intrinsic function ASSOCIATED can test the association status of a defined pointer:

or between a defined pointer and a defined target:

An alternative way to initialize a pointer, also in a specification statement, is to use the NULL function:

                                     

6.3. Pointers Pointers in expressions and assignments

For intrinsic types we can sweep pointers over different sets of target data using the same code without any data movement. Given the matrix manipulation y = B C z, we can write the following code:

For objects of derived type we have to distinguish between pointer and normal assignment. In

the assignment causes first to point at current, whereas

causes current to overwrite first and is equivalent to

                                     

6.4. Pointers Pointer arguments

If an actual argument is a pointer then, if the dummy argument is also a pointer,

  • it returns its final association status to the actual argument note: the target may be undefined!,
  • it may not have the INTENT attribute it would be ambiguous,
  • it must have same rank,
  • it requires an interface block.
  • it receives its association status from the actual argument,

If the dummy argument is not a pointer, it becomes associated with the target of the actual argument:

                                     

6.5. Pointers Pointer functions

Function results may also have the POINTER attribute; this is useful if the result size depends on calculations performed in the function, as in

where the module data_handler contains

The result can be used in an expression but must be associated with a defined target.

                                     

6.6. Pointers Arrays of pointers

These do not exist as such: given

then

would be such an object, but with an irregular storage pattern. For this reason they are not allowed. However, we can achieve the same effect by defining a derived data type with a pointer as its sole component:

and then defining arrays of this data type

where the storage for the rows can be allocated by, for instance,

The array assignment s = t is then equivalent to the pointer assignments s i% r => t i% r for all components.

                                     

6.7. Pointers Pointers as dynamic aliases

Given an array

that is frequently referenced with the fixed subscripts

these references may be replaced by

The subscripts of window are 1: n - m + 1, 1: q - p + 1. Similarly, for tar % u as defined in already, we can use, say, taru => tar % u to point at all the u components of tar, and subscript it as taru 1, 2

The subscripts are as those of tar itself. This replaces yet more of EQUIVALENCE.

In the pointer association

the lower bounds for pointer are determined as if lbound was applied to array_expression. Thus, when a pointer is assigned to a whole array variable, it inherits the lower bounds of the variable, otherwise, the lower bounds default to 1.

Fortran 2003 allows specifying arbitrary lower bounds on pointer association, like

so that the bounds of window become r:r+n-m,s:s+q-p. Fortran 95 does not have this feature; however, it can be simulated using the following trick based on the pointer association rules for assumed shape array dummy arguments:

The source code of an extended example of the use of pointers to support a data structure is in pointer.f90.

                                     

7. Intrinsic procedures

Most of the intrinsic functions have already been mentioned. Here, we deal only with their general classification and with those that have so far been omitted. All intrinsic procedures can be used with keyword arguments:

and many have optional arguments.

The intrinsic procedures are grouped into four categories:

  • elemental - work on scalars or arrays, e.g. ABSa ;
  • inquiry - independent of value of argument which may be undefined, e.g. PRECISIONa ;
  • subroutines, e.g. SYSTEM_CLOCK.
  • transformational - array argument with array result of different shape, e.g. RESHAPEa, b ;

The procedures not already introduced are

Bit inquiry

BIT_SIZE Number of bits in the model

Bit manipulation

BTEST Bit testing IAND Logical AND IBCLR Clear bit IBITS Bit extraction IBSET Set bit IEOR Exclusive IOR Inclusive OR ISHFT Logical shift ISHFTC Circular shift NOT Logical complement

Transfer function, as in

replaces part of EQUIVALENCE

Subroutines

DATE_AND_TIME Obtain date and/or time MVBITS Copies bits RANDOM_NUMBER Returns pseudorandom numbers RANDOM_SEED Access to seed SYSTEM_CLOCK Access to system clock CPU_TIME Returns processor time in seconds
                                     

8.1. Data transfer Formatted input/output

These examples illustrate various forms of I/O lists with some simple formats see below:

Variables, but not expressions, are equally valid in input statements using the read statement:

If an array appears as an item, it is treated as if the elements were specified in array element order.

Any pointers in an I/O list must be associated with a target, and transfer takes place between the file and the targets.

An item of derived type is treated as if the components were specified in the same order as in the type declaration, so

has the same effect as the statement

An object in an I/O list is not permitted to be of a derived type that has a pointer component at any level of component selection.

Note that a zero-sized array may occur as an item in an I/O list. Such an item corresponds to no actual data transfer.

The format specification may also be given in the form of a character expression:

or as an asterisk – this is a type of I/O known as list-directed I/O see below, in which the format is defined by the computer system:

Input/output operations are used to transfer data between the storage of an executing program and an external medium, specified by a unit number. However, two I/O statements, print and a variant of read, do not reference any unit number: this is referred to as terminal I/O. Otherwise the form is:

where unit= is optional. The value may be any nonnegative integer allowed by the system for this purpose.

An asterisk is a variant – again from the keyboard:

A read with a unit specifier allows exception handling:

There a second type of formatted output statement, the write statement:

                                     

8.2. Data transfer Internal files

These allow format conversion between various representations to be carried out by the program in a storage area defined within the program itself.

If an internal file is a scalar, it has a single record whose length is that of the scalar.

If it is an array, its elements, in array element order, are treated as successive records of the file and each has length that of an array element.

An example using a write statement is

that might write

Takings for day 3 are 4329.15 dollars
                                     

8.3. Data transfer List-directed I/O

An example of a read without a specified format for input is

If this reads the input record

in which blanks are used as separators, then i, a, field, flag, and title will acquire the values 10, 6.4, 1.0.0.0 and 2.0.0.0.true. and test respectively, while word remains unchanged.

Quotation marks or apostrophes are required as delimiters for a string that contains a blank.

                                     

8.4. Data transfer Non-advancing I/O

This is a form of reading and writing without always advancing the file position to ahead of the next record. Whereas an advancing I/O statement always repositions the file after the last record accessed, a non-advancing I/O statement performs no such repositioning and may therefore leave the file positioned within a record.

A non-advancing read might read the first few characters of a record and a normal read the remainder.

In order to write a prompt to a terminal screen and to read from the next character position on the screen without an intervening line-feed, we can write

Non-advancing I/O is for external files, and is not available for list-directed I/O.

                                     

8.5. Data transfer Edit descriptors

It is possible to specify that an edit descriptor be repeated a specified number of times, using a repeat count: 10f12.3

The slash edit descriptor see below may have a repeat count, and a repeat count can also apply to a group of edit descriptors, enclosed in parentheses, with nesting:

Entire format specifications can be repeated:

writes 10 integers, each occupying 8 character positions, on each of 20 lines repeating the format specification advances to the next line.

                                     

8.6. Data transfer Control edit descriptors

Control edit descriptors setting conditions:

Control edit descriptors for immediate processing:

                                     

8.7. Data transfer Unformatted I/O

This type of I/O should be used only in cases where the records are generated by a program on one computer, to be read back on the same computer or another computer using the same internal number representations:

                                     

9.1. Operations on external files The open statement

The statement is used to connect an external file to a unit, create a file that is preconnected, or create a file and connect it to a unit. The syntax is

where olist is a list of optional specifiers. The specifiers may appear in any order.

Other specifiers are form and position.

                                     

9.2. Operations on external files The close statement

This is used to disconnect a file from a unit.

as in

                                     

9.3. Operations on external files The inquire statement

At any time during the execution of a program it is possible to inquire about the status and attributes of a file using this statement.

Using a variant of this statement, it is similarly possible to determine the status of a unit, for instance whether the unit number exists for that system.

Another variant permits an inquiry about the length of an output list when used to write an unformatted record.

For inquire by unit

for inquire by file

for inquire by I/O list

As an example

yields

assuming no intervening read or write operations.

Other specifiers are iostat, opened, number, named, formatted, position, action, read, write, readwrite.

Free and no ads
no need to download or install

Pino - logical board game which is based on tactics and strategy. In general this is a remix of chess, checkers and corners. The game develops imagination, concentration, teaches how to solve tasks, plan their own actions and of course to think logically. It does not matter how much pieces you have, the main thing is how they are placement!

online intellectual game →