Array: Difference between revisions

Content added Content deleted
(→‎Fortran: More array facilities.)
Line 42: Line 42:


===[[Fortran]]===
===[[Fortran]]===
Arrays have been available from the start, for each of the allowed types of variables: integer, real, complex, and their different precisions. They can be indexed only with integer values, and definitely not with text strings as in say Snobol. Indexing starts with one, and the size is fixed by the declaration at compile time, thus <lang Fortran> REAL A(66)
Arrays have been available from the start, for each of the allowed types of variables: integer, real, complex, and their different precisions. They can be indexed only with integer values, and definitely not with text strings as in say Snobol. Indexing starts with one, and the size is fixed by the declaration at compile time, thus <lang Fortran> REAL A(66) !Declares an array, elements one to sixty-six.
A(3) = 1.1
A(3) = 1.1 !Assigns a value to the third element of A.
A(2) = 1.1
A(2) = 1.1
A(1) = 1.1</lang>
A(1) = 1.1</lang>
Higher dimensonality is available, with additional indices, thus <code>B(12,6) = 7</code> The type includes the dimensionality so array B can only be referenced with two indices and A only with one, although it is possible to specify something like <code>EQUIVALENCE (A,B)</code> which means that the two names refer to the same storage; the arrays are overlaid. With careful organisation and a good plan, this can have positive benefits. Multi-dimensional arrays are stored in "column-major" order, which is to say that for consecutive elements in storage, the ''left''most subscript varies most rapidly, so the order would be B(1,1), B(2,1), B(3,1), ... B(12,1), B(1,2), B(2,2), ''etc''. This is important when explicit indexing is not used, as when only its name is given in a READ, WRITE, or DATA statement: values are processed in storage order.
Higher dimensonality is available, with additional indices, thus given the declaration <code>INTEGER B(12,9)</code> individual elements would be accessed via the likes of <code>B(12,6) = 7</code> The type includes the dimensionality so array B can only be referenced with two indices and A only with one, although it is possible to specify something like <code>EQUIVALENCE (A,B)</code> which means that the two names refer to the same storage; the arrays are overlaid, even if of different types. With careful organisation and a good plan, this can have positive benefits. Multi-dimensional arrays are stored in "column-major" order, which is to say that for consecutive elements in storage, the ''left''most subscript varies most rapidly, so the order would be B(1,1), B(2,1), B(3,1), ... B(12,1), B(1,2), B(2,2), ''etc''. This is important when explicit indexing is not used, as when only its name is given in a READ, WRITE, or DATA statement: values are processed in storage order.


There is no "array subscript" type or usage, whereby, given <code>INTEGER XLAT(2)</code> element B(i,j) might be accessed via B(XLAT) where XLAT(1) = i and XLAT(2) = j. One must use <code>B(XLAT(1),XLAT(2))</code>
There is no "array subscript" type or usage, whereby, given <code>INTEGER XLAT(2)</code> element B(i,j) might be accessed via B(XLAT) where XLAT(1) = i and XLAT(2) = j. One must use <code>B(XLAT(1),XLAT(2))</code>


An array is identical to a function of integer arguments, so in <code>result = 3*F(X) + 7</code>, the F might be a function (of one parameter, an integer), or, it might be an array of one dimension, unlike with Pascal where F[...] is definitely an array, and F(...) is definitely a function. If a declaration such as <code>COMPLEX F(33)</code> to make it an array does ''not'' appear in that program unit, F will be taken as being a function, and the declaration <code>COMPLEX F</code> should appear since otherwise F would be REAL, not COMPLEX. This could be useful in debugging, where function F will provide checking and trace output, etc. as well as supplying the correct value. Alas, Fortran does not offer the ability to write "palindromic" functions so although <code>N = DAYNUM(Year,Month,Day)</code> is perfectly valid, <code>DAYNUM(Year,Month,Day) = N</code> is not possible with functions, though standard with arrays.
An array is identical to a function of integer arguments, so in <code>result = 3*F(X) + 7</code>, the F might be a function (of one parameter, an integer), or, it might be an array of one dimension - unlike with Pascal where F[...] is definitely an array, and F(...) is definitely a function. If a declaration such as <code>COMPLEX F(33)</code> to make it an array does ''not'' appear in that program unit, F will be taken as being a function, and the declaration <code>COMPLEX F</code> should appear since otherwise F would be REAL, not COMPLEX. This could be useful in debugging, where function F will provide checking and trace output, etc. as well as supplying the correct value. Alas, Fortran does not offer the ability to write "palindromic" functions so although <code>N = DAYNUM(Year,Month,Day)</code> is perfectly valid, <code>DAYNUM(Year,Month,Day) = N</code> is not possible with functions, though standard with arrays.


There is no associative access facility, of the form "what indices of A satisfy this condition", except almost: the INDEX function, which however is allowed only for CHARACTER variables. <code>L = INDEX("sometexts","text")</code> will return 5, the location of the first occasion (counting characters from one) where the second parameter exactly matches a portion of the first.
There is no associative access facility, of the form "what indices of A satisfy this condition", except almost: the INDEX function, which however is allowed only for CHARACTER variables. <code>L = INDEX("sometexts","text")</code> will return 5, the location of the first occasion (counting characters from one) where the second parameter exactly matches a portion of the first.


With F90 came the standardisation of many expanded facilities. Arrays can be defined with any lower bound instead of just one, as in <code>REAL A(1951:2017)</code>, and with it now possible to define compound types, there can be arrays of such aggregates. Type matching remains strict, however. There is also much greater flexibility in manipulating arrays without explicit looping. The assignment above could be done via <code>A(3:1:-1) = 1.1</code> or, more normally, by <code>A(1:3) = 1.1</code> Similarly, there are additional functions applicable to arrays; <code>MAXLOC(A)</code> returns the index of the (first encountered?) maximum value of the array, but there is still no extension for INDEX. A new statement provides some associative processing, as in <code>WHERE(A > 0) A = 1/A</code> as a simple case.
With F90 came the standardisation of many expanded facilities. Arrays can be defined with any lower bound instead of just one, as in <code>REAL A(1951:2017)</code>, and with it now possible to define compound types, there can be arrays of such aggregates. Type matching remains strict, however. There is also much greater flexibility in manipulating arrays without explicit looping. The assignment above could be done via <code>A(3:1:-1) = 1.1</code> or, more normally, by <code>A(1:3) = 1.1</code> The scheme is ''start:'stop:step'' with the '':step'' part unnecessary if it is one, as with DO-loops. Simplicity of syntax can however lead to surprises. If a 4 x 4 portion of array B was selected as a parameter (to some matrix-manipulation routine, say) as in <code>CALL TRANSPOSE(B(5:8,6:9))</code>, then the scattered elements of B would be copied into a 4x4 work area first, because the subroutine deals with array elements in contiguous storage: this is copy-in, copy-out rather than the normal pass-by-reference, and if the arrays are large, this will be very slow as well as producing some subtle differences in behaviour.

Similarly, F90 provides additional functions applicable to arrays; there is a TRANSPOSE, and <code>MAXLOC(A)</code> returns the index of the (first encountered?) maximum value of the array, but there is still no extension for INDEX. However, a new statement provides some more associative processing, as in <code>WHERE(A > 0) A = 1/A</code> for a simple case.


Array sizes are no longer always fixed at compile time: on entry to a subroutine or function it can declare an array of a size determined by that occasion (as in Algol since the 1960s), and arrays can be explicitly allocated and de-allocated storage according to program logic. But, their type and dimensionality remain fixed.
Array sizes are no longer always fixed at compile time: on entry to a subroutine or function it can declare an array of a size determined by that occasion (as in Algol since the 1960s), and arrays can be explicitly allocated and de-allocated storage according to program logic. But, their type and dimensionality remain fixed.