spec

Software for Diffraction

2.3.4.2.1. - Data Array Usage



Data arrays must be declared with the array key word. One- and two-dimensional arrays are declared as:
[shared] [type] array var[cols]
[shared] [type] array var[rows][cols]
On platforms that support System V Interprocess Communication (IPC) calls, the shared keyword causes spec to place the array in shared memory (see below). The type keyword specifies the storage type of the array and may be one of byte, ubyte, short, ushort, long, ulong, long64, ulong64, float, double or string. An initial u denotes the "unsigned" version of the data type. The short and ushort types are 16-bit (two-byte) integers. The long and ulong types are 32-bit (four-byte) integers. The long64 and ulong64 types are 64-bit (eight-byte) integers. The float type uses four bytes per element. The double type uses eight bytes per element. The default data type is double.

The array name var is an ordinary spec variable name. Arrays are global by default, although they may also be declared local within statement blocks.

Unlike traditional spec associative arrays, which can store and be indexed by arbitrary strings or numbers, a data array is indexed by consecutive integers (starting from zero), and can hold only numbers, or in the case of string arrays, only strings.

Operations on these arrays can be performed on all elements of the array at once, or on one or more blocks of elements. Consider the following example:
array a[20]
a = 2
a[3] = 3
a[10:19] = 4
a[2,4,6,10:15] = 5
The first expression assigns the value 2 to all twenty elements of the array. The second expressions assigns 3 to one element. The third assign the value 4 to the tenth through last element. The final expression assigns the value 5 to the elements listed.

A negative number as an array index counts elements from the end of the array, with a[-1] referring to the last element of a.

As per the usual conventions, the first index is row and the second is column. Note, however, spec considers arrays declared with one dimension to be a single row. For example,
array a[20]
is a one-row, twenty-column array. Use
array a[20][1]
to declare a 20-row, one-column array.

Also note well, all operations between two arrays are defined as element-by-element operations, not matrix operations, which are currently unimplemented in spec. In the following example:
array a[5][5], b[5][5], c[5][5]
c = a * b
c[i][j] is the product a[i][j]* b[i][j] for each i and j.

When two array operands have different dimensions the operations are performed on the elements that have dimensions in common. In the case:
array a[5][5], b[5], c[5][5]
c = a * b
only the first row of c will have values assigned, since b only has one row. The remaining elements of c are unchanged by the assignment.

Portions of the array can be accessed using the subarray syntax, which uses colons and commas, as in the following examples:
array a[10][10]
a[1]                # second row of a
a[2:4][]            # rows 2 to 4
a[][2:]             # all rows, cols 2 to last
a[1,3,5,7,9][3:7]   # odd rows and cols 3 to 7


The elements of an array can be accessed in reverse order, as in:
a = x[-1:0]
which will assign to a the reversed elements of x. Note, though, that presently, an assignment such as x = x[-1:0] will not work properly, as spec will not make a temporary copy of the elements. However, x = x[-1:0]+0 will work.

The functions fabs(), int(), cos(), acos(), sin(), asin(), tan(), atan(), exp(), exp10(), log(), log10(), pow() and sqrt() can all take arrays as an argument. The functions perform the operation on each element of the array argument and return the results in an array of the same dimension as the argument array.

The operations <, <=, !=, ==, > and >= can be used with array arguments. The Boolean result (0 or 1) will be assigned to each element of an array returned as the result of the operation, based on the element-by-element comparison of the operands.

The bit-wise operators ~, |, &, >> and << can also be used with array operands.

Note, spec generally uses double-precision floating point for storing intermediate values and for mathematical operations. Double-precision floating point has only 52 bits for the significand (the remaining 12 bits are for sign and exponent). Thus, for most operations the 64-bit types will only maintain 52 bits of significance. (The 64-bit integer types were added in spec release 6.01.)