Previous | Contents | Index |
For logical assignment statements, the variable must be of logical type and the expression can be of logical or numeric type.
If necessary, the expression is converted to the same type and kind as the variable.
The following examples demonstrate valid logical assignment statements:
PAGEND = .FALSE. PRNTOK = LINE .LE. 132 .AND. .NOT. PAGEND ABIG = A.GT.B .AND. A.GT.C .AND. A.GT.D LOGICAL_VAR = 123 ! Moves binary value of 123 to LOGICAL_VAR |
For character assignment statements, the variable and expression must be of character type and have the same kind parameter.
The variable and expression can have different lengths. If the length of the expression is greater than the length of the variable, the character expression is truncated on the right. If the length of the expression is less than the length of the variable, the character expression is filled on the right with blank characters.
If you assign a value to a character substring, you do not affect character positions in any part of the character scalar variable not included in the substring. If a character position outside of the substring has a value previously assigned, it remains unchanged. If the character position is undefined, it remains undefined.
The following examples demonstrate valid and invalid character assignment statements. (In the valid examples, all variables are of type character.)
Valid | |
FILE = 'PROG2' | |
REVOL(1) = 'MAR'//'CIA' | |
LOCA(3:8) = 'PLANT5' | |
TEXT(I,J+1)(2:N-1) = NAME//X | |
Invalid | Explanation |
'ABC' = CHARS | Left element must be a character variable, array element, or substring reference. |
CHARS = 25 | Expression does not have a character data type. |
STRING = 5HBEGIN | Expression does not have a character data type. Note that Hollerith constants are numeric, not character. |
In derived-type assignment statements, the variable and expression must be of the same derived type. There must be no accessible interface block with defined assignment for objects of this derived type.
The derived-type assignment is performed as if each component of the expression is assigned to the corresponding component of the variable. Pointer assignment is performed for pointer components, and intrinsic assignment is performed for nonpointer components.
The following example demonstrates derived-type assignment:
TYPE DATE LOGICAL(1) DAY, MONTH INTEGER(2) YEAR END TYPE DATE TYPE(DATE) TODAY, THIS_WEEK(7) TYPE APPOINTMENT ... TYPE(DATE) APP_DATE END TYPE TYPE(APPOINTMENT) MEETING DO I = 1,7 CALL GET_DATE(TODAY) THIS_WEEK(I) = TODAY END DO MEETING%APP_DATE = TODAY |
Array assignment is permitted when the array expression on the right has the same shape as the array variable on the left, or the expression on the right is a scalar.
If the expression is a scalar, and the variable is an array, the scalar value is assigned to every element of the array.
If the expression is an array, the variable must also be an array. The array element values of the expression are assigned (element by element) to corresponding elements of the array variable.
A many-one array section is a vector-valued subscript that has two or more elements with the same value. In intrinsic assignment, the variable cannot be a many-one array section because the result of the assignment is undefined.
In the following example, X and Y are arrays of the same shape:
X = Y |
The corresponding elements of Y are assigned to those of X element by element; the first element of Y is assigned to the first element of X, and so forth. The processor can perform the element-by-element assignment in any order.
The following example shows a scalar assigned to an array:
B(C+1:N, C) = 0 |
This sets the elements B (C+1,C), B (C+2,C),...B (N,C) to zero.
The following example causes the values of the elements of array A to be reversed:
REAL A(20) ... A(1:20) = A(20:1:-1) |
Defined assignment specifies an assignment operation. It is defined by a subroutine subprogram containing a generic interface block with the specifier ASSIGNMENT(=). The subroutine is specified by a SUBROUTINE or ENTRY statement that has two nonoptional dummy arguments.
Defined elemental assignment is indicated by specifying ELEMENTAL in the SUBROUTINE statement.
The dummy arguments represent the variable and expression, in that order. The rank (and shape, if either or both are arrays), type, and kind parameters of the variable and expression in the assignment statement must match those of the corresponding dummy arguments.
The dummy arguments must not both be numeric, or of type logical or character with the same kind parameter.
If the variable in an elemental assignment is an array, the defined assignment is performed element-by-element, in any order, on corresponding elements of the variable and expression. If the expression is scalar, it is treated as if it were an array of the same shape as the variable with every element of the array equal to the scalar value of the expression.
In ordinary assignment involving pointers, the pointer is an alias for its target. In pointer assignment, the pointer is associated with a target. If the target is undefined or disassociated, the pointer acquires the same status as the target. The pointer assignment statement has the following form:
|
pointer-object
Is a variable name or structure component declared with the POINTER attribute.target
Is a variable or expression. Its type and kind parameters, and rank must be the same as pointer-object. It cannot be an array section with a vector subscript.
If the target is a variable, it must have the POINTER or TARGET attribute, or be a subobject whose parent object has the TARGET attribute.
If the target is an expression, the result must be a pointer.
If the target is not a pointer (it has the TARGET attribute), the pointer object is associated with the target.
If the target is a pointer (it has the POINTER attribute), its status determines the status of the pointer object, as follows:
A pointer must not be referenced or defined unless it is associated with a target that can be referenced or defined.
When pointer assignment occurs, any previous association between the pointer object and a target is terminated.
Pointers can also be assigned for a pointer structure component by execution of a derived-type intrinsic assignment statement or a defined assignment statement.
Pointers can also become associated by using the ALLOCATE statement to allocate the pointer.
Pointers can become disassociated by deallocation, nullification of the pointer (using the DEALLOCATE or NULLIFY statements), or by reference to the NULL intrinsic function.
The following are examples of pointer assignments:
HOUR => MINUTES(1:60) ! target is an array M_YEAR => MY_CAR%YEAR ! target is a structure component NEW_ROW%RIGHT => CURRENT_ROW ! pointer object is a structure component PTR => M ! target is a variable POINTER_C => NULL () ! reference to NULL intrinsic |
The following example shows a target as a pointer:
INTEGER, POINTER :: P, N INTEGER, TARGET :: M INTEGER S M = 14 N => M ! N is associated with M P => N ! P is associated with M through N S = P + 5 |
The value assigned to S is 19 (14 + 5).
The WHERE statement and construct let you use masked array assignment, which performs an array operation on selected elements. This kind of assignment applies a logical test to an array on an element-by-element basis.
The WHERE statement takes the following form:
|
The WHERE construct takes the following form:
|
mask-expr1, mask-expr2
Are logical array expressions (called mask expressions).assign-stmt
Is an assignment statement of the form: array variable = array expression.name
Is the name of the WHERE construct.where-body-stmt
Is one of the following:
- An assign-stmt
This can be a defined assignment only if the routine implementing the defined assignment is elemental.- A WHERE statement or construct
If a construct name is specified in a WHERE statement, the same name must appear in the corresponding END WHERE statement. The same construct name can optionally appear in any ELSEWHERE statement in the construct. (ELSEWHERE cannot specify a different name.)
In each assignment statement, the mask expression, the variable being assigned to, and the expression on the right side, must all be conformable. Also, the assignment statement cannot be a defined assignment.
Only the WHERE statement (or the first line of the WHERE construct) can be labeled as a branch target statement.
The following is an example of a WHERE statement:
INTEGER A, B, C DIMENSION A(5), B(5), C(5) DATA A /0,1,1,1,0/ DATA B /10,11,12,13,14/ C = -1 WHERE(A .NE. 0) C = B / A |
The resulting array C contains: --1,11,12,13, and --1.
The assignment statement is only executed for those elements where the mask is true. Think of the mask expression as being evaluated first into a logical array that has the value true for those elements where A is positive. This array of trues and falses is applied to the arrays A, B and C in the assignment statement. The right side is only evaluated for elements for which the mask is true; assignment on the left side is only performed for those elements for which the mask is true. The elements for which the mask is false do not get assigned a value.
In a WHERE construct, the mask expression is evaluated first and only once. Every assignment statement following the WHERE is executed as if it were a WHERE statement with "mask-expr1" and every assignment statement following the ELSEWHERE is executed as if it were a WHERE statement with ".NOT. mask-expr1". If ELSEWHERE specifies "mask-expr2", it is executed as "(.NOT. mask-expr1) .AND. mask-expr2" during the processing of the ELSEWHERE statement.
You should be careful if the statements have side effects, or modify each other or the mask expression.
The following is an example of the WHERE construct:
DIMENSION PRESSURE(1000), TEMP(1000), PRECIPITATION(1000) WHERE(PRESSURE .GE. 1.0) PRESSURE = PRESSURE + 1.0 TEMP = TEMP - 10.0 ELSEWHERE PRECIPITATION = .TRUE. ENDWHERE |
The mask is applied to the arguments of functions on the right side of the assignment if they are considered to be elemental functions. Only elemental intrinsics are considered elemental functions. Transformational intrinsics, inquiry intrinsics, and functions or operations defined in the subprogram are considered to be nonelemental functions.
Consider the following example using LOG, an elemental function:
WHERE(A .GT. 0) B = LOG(A) |
The mask is applied to A, and LOG is executed only for the positive values of A. The result of the LOG is assigned to those elements of B where the mask is true.
Consider the following example using SUM, a nonelemental function:
REAL A, B DIMENSION A(10,10), B(10) WHERE(B .GT. 0.0) B = SUM(A, DIM=1) |
Since SUM is nonelemental, it is evaluated fully for all of A. Then, the assignment only happens for those elements for which the mask evaluated to true.
Consider the following example:
REAL A, B, C DIMENSION A(10,10), B(10), C(10) WHERE(C .GT. 0.0) B = SUM(LOG(A), DIM=1)/C |
Because SUM is nonelemental, all of its arguments are evaluated fully regardless of whether they are elemental or not. In this example, LOG(A) is fully evaluated for all elements in A even though LOG is elemental. Notice that the mask is applied to the result of the SUM and to C to determine the right side. One way of thinking about this is that everything inside the argument list of a nonelemental function does not use the mask, everything outside does.
On a generalized form of masked array assignment, see Section 4.2.5.
4.2.5 FORALL Statement and Construct
The FORALL statement and construct is a generalization of the Fortran 95/90 masked array assignment (WHERE statement and construct). It allows more general array shapes to be assigned, especially in construct form.
FORALL is a feature of Fortran 95. It takes the following form:
|
The FORALL construct takes the following form:
|
triplet-spec
Is a triplet specification with the following form:
- subscript-name = subscript-1 : subscript-2 [:stride]
The subscript-name must be a scalar of type integer. It is valid only within the scope of the FORALL; its value is undefined on completion of the FORALL.
The subscripts and stride cannot contain a reference to any subscript-name in triplet-spec.
The stride cannot be zero. If it is omitted, the default value is 1.
Evaluation of an expression in a triplet specification must not affect the result of evaluating any other expression in another triplet specification.
mask-expr
Is a logical array expression (called the mask expression). If it is omitted, the value .TRUE. is assumed. The mask expression can reference the subscript name in triplet-spec.assign-stmt
Is an assignment statement or a pointer assignment statement. The variable being assigned to must be an array element or array section and must reference all subscript names included in all triplet-specs.name
Is the name of the FORALL construct.forall-body-stmt
Is one of the following:
- An assignment-stmt
- A WHERE statement or construct
The WHERE statement and construct use a mask to make the array assignments (see Section 4.2.4).- A FORALL statement or construct
If a construct name is specified in the FORALL statement, the same name must appear in the corresponding END FORALL statement.
A FORALL statement is executed by first evaluating all bounds and stride expressions in the triplet specifications, giving a set of values for each subscript name. The FORALL assignment statement is executed for all combinations of subscript name values for which the mask expression is true.
The FORALL assignment statement is executed as if all expressions (on both sides of the assignment) are completely evaluated before any part of the left side is changed. Valid values are assigned to corresponding elements of the array being assigned to. No element of an array can be assigned a value more than once.
A FORALL construct is executed as if it were multiple FORALL statements, with the same triplet specifications and mask expressions. Each statement in the FORALL body is executed completely before execution begins on the next FORALL body statement.
Any procedure referenced in the mask expression or FORALL assignment statement must be pure.
Pure functions can be used in the mask expression or called directly in a FORALL statement. Pure subroutines cannot be called directly in a FORALL statement, but can be called from other pure procedures.
Consider the following:
FORALL(I = 1:N, J = 1:N, A(I, J) .NE. 0.0) B(I, J) = 1.0 / A(I, J) |
This statement takes the reciprocal of each nonzero element of array A(1:N, 1:N) and assigns it to the corresponding element of array B. Elements of A that are zero do not have their reciprocal taken, and no assignments are made to corresponding elements of B.
Every array assignment statement and WHERE statement can be written as a FORALL statement, but some FORALL statements cannot be written using just array syntax. For example, the preceding FORALL statement is equivalent to the following:
WHERE(A /= 0.0) B = 1.0 / A |
It is also equivalent to:
FORALL (I = 1:N, J = 1:N) WHERE(A(I, J) .NE. 0.0) B(I, J) = 1.0/A(I, J) END FORALL |
However, the following FORALL example cannot be written using just array syntax:
FORALL(I = 1:N, J = 1:N) H(I, J) = 1.0/REAL(I + J - 1) |
This statement sets array element H(I, J) to the value 1.0/REAL(I + J - 1) for values of I and J between 1 and N.
Consider the following:
TYPE MONARCH INTEGER, POINTER :: P END TYPE MONARCH TYPE(MONARCH), DIMENSION(8) :: PATTERN INTEGER, DIMENSION(8), TARGET :: OBJECT FORALL(J=1:8) PATTERN(J)%P => OBJECT(1+IEOR(J-1,2)) |
This FORALL statement causes elements 1 through 8 of array PATTERN to point to elements 3, 4, 1, 2, 7, 8, 5, and 6, respectively, of OBJECT. IEOR can be referenced here because it is pure.
The following example shows a FORALL construct:
FORALL(I = 3:N + 1, J = 3:N + 1) C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J) D(I, J) = C(I, J) END FORALL |
The assignment to array D uses the values of C computed in the first statement in the construct, not the values before the construct began execution.
Previous | Next | Contents | Index |