The PRIMDAT package (see SUN/39) provides a range of symbolic constants, functions and
subroutines which aid in the processing of numeric data. Facilities to cope with all HDS numeric data
types are included; manipulation involving the non-numeric types, _LOGICAL
and _CHAR can be done
using the CHR routines as described in Section 11.
The names of the routines and constants described below usually end with a one or two letter code
appropriate to the data type to which they apply. These codes are R, D, I, W, UW, B
or UB
corresponding to the HDS data types _REAL, _DOUBLE, _INTEGER, _WORD, _UWORD, _BYTE,
and
_UBYTE respectively. For example, VAL__BADR
is the symbolic constant which represents the bad
data value for _REAL data, whereas VAL__BADUB
represents the bad data value for _UBYTE
data.
VAL, NUM and VEC routines.
The example program in Section 12 contained a subroutine which simply calculated the square root of the input data array and dealt correctly with bad data values. However the PRIMDAT package contains a set of general purpose routines which includes just such a subroutine. There are three sets of routines, which can be summarised as follow:
The name of a routine consists of one of the above prefixes, plus an indication of the function it
performs and the type of data it expects. For example, the name of the subroutine which takes the
square root of a double-precision input data array is VEC_SQRTD
. There are also type conversion
routines. For example, VEC_RTOI
converts a real array to an integer one. A list of the formats of the
routines is shown in the table on the following page.
The tables below indicate the range of arithmetic operations available. The functions in the left-hand
table are implemented for all the HDS numeric types. The trigonometric functions in the right-hand
table are implemented only for types _REAL and _DOUBLE; those trigonometric functions whose name
ends with D
operate in degrees; the others use radians.
Func | Narg | Operation performed |
ADD | 2 | addition: ARG1 + ARG2 |
SUB | 2 | subtraction: ARG1 − ARG2 |
MUL | 2 | multiplication: ARG1 ∗ ARG2 |
DIV | 2 | *(floating) division: ARG1 / ARG2 |
IDV | 2 | **(integer) division: ARG1 / ARG2 |
PWR | 2 | raise to power: ARG1 ∗∗ ARG2 |
NEG | 1 | negate (change sign): −ARG |
SQRT | 1 | square root: √ARG |
LOG | 1 | natural logarithm: ln(ARG) |
LG10 | 1 | common logarithm: log10(ARG) |
EXP | 1 | exponential: exp(ARG) |
ABS | 1 | absolute value: |ARG| |
NINT | 1 | nearest integer value to ARG |
INT | 1 | Fortran AINT (truncation to integer) fn. |
MAX | 2 | maximum: max(ARG1,ARG2) |
MIN | 2 | minimum: min(ARG1,ARG2) |
DIM | 2 | Fortran DIM (positive difference) fn. |
MOD | 2 | Fortran MOD (remainder) fn. |
SIGN | 2 | Fortran SIGN (transfer of sign) fn. |
Func | Narg | Operation performed |
SIN | 1 | sin(ARG) |
SIND | 1 | sin(ARG) |
COS | 1 | cos(ARG) |
COSD | 1 | cos(ARG) |
TAN | 1 | tan(ARG) |
TAND | 1 | tan(ARG) |
ASIN | 1 | sin−1(ARG) |
ASND | 1 | sin−1(ARG) |
ACOS | 1 | cos−1(ARG) |
ACSD | 1 | cos−1(ARG) |
ATAN | 1 | tan−1(ARG) |
ATND | 1 | tan−1(ARG) |
ATN2 | 2 | Fortran ATAN2 |
(inverse tangent) function | ||
AT2D | 2 | VAX Fortran ATAN2D |
(inverse tangent) function | ||
SINH | 1 | sinh(ARG) |
COSH | 1 | cosh(ARG) |
TANH | 1 | tanh(ARG) |
The following table gives the format of the routines as described above;
Format of routine | Example |
RESULT = VAL_funcx (BAD, ARG, STATUS) | PROOT = VAL_SQRTR (BAD, P, STATUS) |
RESULT = VAL_funcx (BAD, ARG, ARG1, STATUS) | BSUM = VAL_ADDUB (BAD, B1, B2, STATUS) |
RESULT = VAL_xTOy (BAD, ARG, STATUS) | IP = VAL_RTOI (BAD, P, STATUS) |
RESULT = NUM_funcx (ARG) | PLOG = NUM_LOGR (P) |
RESULT = NUM_funcx (ARG, ARG1) | ICUBE = NUM_PWRI (I, 3) |
RESULT = NUM_xTOy (ARG) | P = NUM_DTOR (D) |
CALL VEC_funcx (BAD, ARG, RESULT, IERR, NERR, STATUS) | CALL VEC_SINR (BAD, P, SINP, I, N, STATUS) |
CALL VEC_funcx (BAD, ARG, ARG1, RESULT, IERR, NERR, STATUS) | CALL VEC_ADDD (BAD, A, B, C, I, N, STATUS) |
CALL VEC_xTOy (BAD, ARG, RESULT, IERR, NERR, STATUS) | CALL VEC_RTOI (BAD, P, IP, I, N, STATUS) |
The arguments are summarised below. BAD
is a logical value specifying whether bad input arguments
are to be recognised; N
is the number of elements in the case of VAL routines; ARG
, ARG1
and ARG2
are
the input arguments, and RESULT
is the result. (In the case of the VEC routines the input arguments
ARG, ARG1, ARG2
and the RESULT
are vectorised arrays, whereas they represent single values in the
cases of the VAL and NUM routines.) IERR
is an integer output argument which identifies the first
array element to generate a numerical error, NERR
is an integer output argument which returns a count
of the number of numerical errors which occur, and finally STATUS
is the usual integer
status.
Thus the subroutine call in ADAM_EXAMPLES:SQROOT.FOR could be replaced with the call below:
The program SQROOT.FOR assumes that the input array is of REAL type – a safe assumption as the NDF_MAP routine used type ’_REAL’ which means that the array will be mapped as _REAL regardless of the actual type in the NDF. An obvious improvement would be to test the actual type of the data array, map with that type, and use an appropriate subroutine to take the square root12. ADAM_EXAMPLES:SQROOTGEN.FOR contains these modifications.The PRIMDAT routines are linked using the options file PRM_LINK as shown below:
Symbolic constants.
The set of symbolic constants provided within the PRIMDAT package is made available
to a program by including the file with logical name PRM_PAR
. These constants relate to
machine-specific numeric quantities – for example, the range of values which can be represented
for a particular data type or the number of bytes per value used for each data type.
Programs must use such symbolic constants rather than the numbers which they represent.
For example, the largest integer which can be represented on a VAX is 2147483647 (i.e.
231−1). A
program which uses this number in arithmetic checks etc. will not be portable to a machine with
different arithmetic capabilities. However, software which uses the appropriate symbolic
constant (called VAL__MAXI) can be ported simply by providing an appropriate version of
PRM_PAR
.
The complete set of symbolic constants is represented in the table below, where the final x
in the name is one
of R, D, I, W, UW, B
or UB
as indicated above. The data type of each symbolic constant matches that of the
data type to which it applies, except in the cases of VAL__NBx
and VAL__SZx
which are, of course, integers.
Constant | Quantity |
VAL__BADx | Bad data value |
VAL__EPSx | Machine precision – minimum ϵ such that 1 is distinguishable from (1+ϵ) |
VAL__MAXx | Maximum (most positive) non-bad value |
VAL__MINx | Minimum (most negative) non-bad value |
VAL__NBx | Number of bytes used by a value |
VAL__SMLx | Smallest positive non-zero value |
VAL__SZx | Number of characters needed to format value as a decimal string |
12The general problem of producing and maintaining a set of subroutines which perform the same function for different data types is addressed by the GENERIC package described in SUN/7.