Multidimensional Arrays
The arrays we have seen so far this semester are one-dimensional arrays. We often visualize such arrays as being laid out in a single row.
A two-dimensional array can be visualized as a table made up of several rows and columns. If the columns are a single dimension array then a table (two-dimensional array) can be thought of as a series of single dimensional arrays (columns).
Above, single dimension array, below, table, two-dimensional array.
Why think of a single-dimension array as a column? Because in physical memory, arrays are stored by column, such that all of column 1's contents reside consecutively then column 2's, column 3's, and so on. Such arrangement in memory is known as column major order. Not all programming languages will be column major order, some will be row major order.
Declaring Two Dimensional Arrays
PROGRAM twoD IMPLICIT NONE INTEGER, PARAMETER :: SIZE = 5 INTEGER :: array(SIZE, SIZE) INTEGER :: i INTEGER :: j DO i = 1, 5 DO j = 1, 5 array(i, j) = j END DO END DO DO i = 1, 5 DO j = 1, 5 WRITE(*,*) "Array (", i, ",", j, ") = ", array(i,j) END DO END DO END PROGRAM twoD
The program above will iterate through the entire array first initializing the array and then printing the array contents.
Output:
Array ( 1 , 1 ) = 1 Array ( 1 , 2 ) = 2 Array ( 1 , 3 ) = 3 Array ( 1 , 4 ) = 4 Array ( 1 , 5 ) = 5 Array ( 2 , 1 ) = 1 Array ( 2 , 2 ) = 2 Array ( 2 , 3 ) = 3 Array ( 2 , 4 ) = 4 Array ( 2 , 5 ) = 5 Array ( 3 , 1 ) = 1 Array ( 3 , 2 ) = 2 Array ( 3 , 3 ) = 3 Array ( 3 , 4 ) = 4 Array ( 3 , 5 ) = 5 Array ( 4 , 1 ) = 1 Array ( 4 , 2 ) = 2 Array ( 4 , 3 ) = 3 Array ( 4 , 4 ) = 4 Array ( 4 , 5 ) = 5 Array ( 5 , 1 ) = 1 Array ( 5 , 2 ) = 2 Array ( 5 , 3 ) = 3 Array ( 5 , 4 ) = 4 Array ( 5 , 5 ) = 5Question, does i represent the rows or the columns of this table?
Memory. How in memory are arrays stored?
Let's change the problem above.
INTEGER, PARAMETER :: COLSIZE = 3 INTEGER, PARAMETER :: ROWSIZE = 2 INTEGER :: array(ROWSIZE, COLSIZE) INTEGER :: i INTEGER :: j DO i = 1, ROWSIZE DO j = 1, COLSIZE array(i, j) = j END DO END DO DO i = 1, ROWSIZE DO j = 1, COLSIZE WRITE(*,*) "Array (", i, ",", j, ") = ", array(i,j) END DO END DOOutput:
Array ( 1 , 1 ) = 1 Array ( 1 , 2 ) = 2 Array ( 1 , 3 ) = 3 Array ( 2 , 1 ) = 1 Array ( 2 , 2 ) = 2 Array ( 2 , 3 ) = 3
But in memory, the elements are stored as follows: (by columns)
(1, 1) (2, 1) (1, 2) (2, 2) (1, 3) (2, 3)
Example, sum each row and each column
Data File
3 4 5 10 1 2
Which equals the following array
3 4 5 10 1 2Output:
Column 1 Sum 9 Column 2 Sum 16 Row 1 Sum 7 Row 2 Sum 15 Row 3 Sum 3Code
PROGRAM sum IMPLICIT NONE INTEGER, PARAMETER :: ROWSIZE = 3 INTEGER, PARAMETER :: COLSIZE = 2 INTEGER :: array(ROWSIZE, COLSIZE) INTEGER :: rowsum(ROWSIZE) INTEGER :: colsum(COLSIZE) INTEGER :: row INTEGER :: col INTEGER :: ierror INTEGER :: rowc = 1 INTEGER :: colc = 1 rowsum = 0 colsum = 0 OPEN(UNIT = 8, FILE = "data", STATUS = "OLD", ACTION = "READ", IOSTAT = ierror) IF (ierror == 0) THEN DO row = 1, ROWSIZE DO col = 1, COLSIZE READ(8, *) array(row, col) END DO END DO DO row = 1, ROWSIZE DO col = 1, COLSIZE colsum(col) = colsum(col) + array(row, col) rowsum(row) = rowsum(row) + array(row, col) END DO END DO DO col = 1, COLSIZE WRITE(*,*) "Column ", col, " Sum ", colsum(col) END DO DO row = 1, ROWSIZE WRITE(*,*) "Row ", row, " Sum ", rowsum(row) END DO ELSE WRITE(*,*) "Couldn't open file!" END IF CLOSE(UNIT = 8) END PROGRAM sum
Arrays Beyond Two Dimensions
According to the text an array can have up to seven different subscripts (dimensions).
Above is a possible visualization of a three dimensional array.
Example, Declare a 3D array and initialize its values to be the plane index times the row index times the column index. Print the results by plane.
Plane # 1 1 2 3 2 4 6 Plane # 2 2 4 6 4 8 12 Plane # 3 3 6 9 6 12 18Code
PROGRAM threeD IMPLICIT NONE INTEGER, PARAMETER :: NUMPLANE = 3 INTEGER, PARAMETER :: NUMROW = 2 INTEGER, PARAMETER :: NUMCOL = 3 INTEGER :: array (NUMPLANE, NUMROW, NUMCOL) INTEGER :: plane INTEGER :: row INTEGER :: col DO plane = 1, NUMPLANE DO row = 1, NUMROW DO col = 1, NUMCOL array(plane, row, col) = plane * row * col END DO END DO END DO DO plane = 1, NUMPLANE WRITE(*,*) "Plane #", plane DO row = 1, NUMROW WRITE(*,*) (array(plane, row, col), col = 1, NUMCOL) END DO END DO END PROGRAM threeD
Elemental Intrinsic Functions
Such functions are specified for scalar arguments but may also be applied to array arguments.
REAL :: x(4) = (/ 0.0, 1.1, 2.2, 3.3 /) REAL :: y(4) y = SIN(x)The result is the same as if the function were applied to each element of the array. The shape of the resulting array must be the same as the input argument.
Inquiry Intrinsic Functions
This type of function will return a value that is dependent on the properties of the object being evaluated.
LBOUND(array) - Returns ALL of the lower bounds of array.
INTEGER :: array (NUMPLANE, NUMROW, NUMCOL) WRITE(*,*) "LBOUND is ", LBOUND(array) LBOUND is 1 1 1LBOUND(array, dim) - Returns the lower bound of dim of array.
There is a similiar function called UBOUND.
SHAPE(array) - Returns the shape of array.
WRITE(*,*) "SHAPE is ", SHAPE(array) SHAPE is 3 2 3
SIZE(array) - Returns the number of elements in the array.
WRITE(*,*) "SIZE is ", SIZE(array) SIZE is 18
Transformational Intrinsic Functions (Appendix B has much more information)
These function have one or more array-valued arguments or an array-valued result. The difference between elemental and transformational is that transformational functions operate on arrays as a whole.
INTEGER :: x(5) = (/ 1, 2, 3, 4, 5 /) INTEGER :: y y = SUM(x) WRITE(*,*) yThe value of y is 15.
The FORTRAN 90 WHERE Construct
Let's say we have an array val and we want the LOG of each element in val to be stored in a second array called logval. However, some of the values in val are not positive and we want those values to be assigned a value of -1 in logval.
One way to accomplish this:
DO i = 1, 3 DO j = 1, 3 IF(val(i,j) > 0) THEN logval(i,j) = LOG(val(i,j)) ELSE logval(i,j) = -1 END IF END DO END DOThe WHERE construct will help accomplish the same task on an element by element basis.
WHERE (val > 0) logval = LOG(val) ELSEWHERE logval = - 1 END WHEREWhich is better? That is, which would be faster and save the CPU some processing? Difficult to say without a way to time. Learning to time the two approaches might be an interesting test if we noticed the performance of either method declining for a large number of array elements.