Array: Difference between revisions

1,671 bytes added ,  7 years ago
→‎Fortran: Associations.
m (Not a task; remove erroneous task headers)
(→‎Fortran: Associations.)
Line 42:
 
===[[Fortran]]===
Arrays have been available from the start, for each of the allowed standard types of variables: integer, real, complex, logical, and character, and their different precisions. They can be indexed only with integer values, and definitely not with text strings as in say Snobol - though one could place a short text into a small CHARACTER variable that is equivalenced to an INTEGER variable and use that integer as in a "hash table" scheme, possibly to good effect. 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 !Assigns a value to the third element of A.
A(2) = 1.1
A(1) = 1.1</lang>
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. Thus, element B(12,6) is the sixth element of row twelve, and the next along in storage would be B(1,7), which is not the seventh element of row twelve.
 
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 because undeclared names have a type of INTEGER if they start with the letters I, J, K, L, M, or N, otherwise REAL. 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 <code>INDEX</code> 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.
Line 56:
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 assignments 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 <code>TRANSPOSE</code> function, and <code>MAXLOC(A)</code> returns the index of the (first encountered?) maximum value of the array, but there is still no extension for <code>INDEX</code> to other types. However, a new statementstatements providesprovide some more associative processing, as in <code>WHERE(A > 0) A = 1/A</code> for a simple case, and similarly, <code>FOR ALL (I = 1:N, A(I) > 0) A(I) = 1/A(I)</code> potentially executes every assignment in parallel. Even so, this is still not an associative memory usage whereby the memory storage device identifies matching indices by its own mysterious inner workings, as with on-chip L1 "cache" memory and the like.
 
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.
 
Arrays remain resolutely rectilinear in shape. There is no direct facility to enable "triangular" arrays, still less ragged arrays. Triangular (and potentially other shape) arrays can be attained with a little effort: most simply, use a rectilinear array and waste the unused portion, otherwise, use a one-dimensional array and calculate offsets into it. But it may be possible to employ ''two'' triangular arrays, that can be fitted into a rectilinear array, possibly with special treatment of the diagonal elements; if so, one must be rigorous about keeping track of which has what subscripts! As for ragged arrays, F90 facilities are required: consider <lang Fortran> TYPE AROW
REAL, ALLOCATABLE:: COL(:)
END TYPE AROW
TYPE(AROW) A(66)</lang>
This declares an array of sixty-six rows, where A(r,c) would be accessed via <code>A(r).COL(c)</code>, but first the code would have to execute <code>ALLOCATE(A(r).COL(first:last))</code> for every row that is to be used to acquire storage for it. Such usage will not be as swift as with plain arrays.
 
===[[Pascal]]===
1,220

edits