!standard G (00) 03-02-21 AI95-00296/01
!class amendment 02-06-07
!status received 02-06-07
!priority Medium
!difficulty Medium
!subject Vector and matrix operations
!summary
The vector and matrix operations in ISO/IEC 13813 are added to Ada.Numerics in
Annex G.
!problem
A number of secondary standards for Ada 83 were produced for the numerics area.
Most of the functionality of these standards was incorporated into Ada 95 (some
in the core language and some in the Numerics Annex) but two packages from
ISO/IEC 13813 were not. These are generic packages for the manipulation of real
and complex vectors and matrices.
The UK was asked to review the situation and to make a recommendation; they
recommended that if Ada were amended then consideration should be given to
including the packages within the Numerics annex.
The packages can be implemented entirely in Ada and thus present little burden
to implementors. Providing secondary standards has not proved satisfactory
because they are not sufficiently visible to the user community as a whole.
!proposal
It is proposed that two generic packages be added to the numerics annex. They
are Ada.Numerics.Generic_Real_Arrays and Ada.Numerics.Generic_Complex_Arrays.
They are included as a new subclause G.3 in order to avoid excessive
renumbering of other clauses.
However, if rearrangement of the Annex were deemed acceptable then it might be
better to put the real arrays package in G.1 (any other non-complex numeric
library packages might then also be in G.1), to renumber G.1 (Complex
Arithmetic) as G.2 and G.2 (Numeric Performance Requirements) as G.3. The
complex arrays package could then be G.2.5.
!wording
Add a new clause G.3 as follows
G.3 Vector and matrix manipulation
Types and operations for the manipulation of real vectors and matrices are
provided in Generic_Real_Arrays, which is defined in G.3.1. Types and
operations for the manipulation of complex vectors and matrices are provided in
Generic_Complex_Arrays, which is defined in G.3.2. Both of these library units
are generic children of the predefind package Numerics (see A.5).
??? do we need non-generic equivalents ???
G.3.1 Real Vectors and Matrices
The generic library package Numerics.Generic_Real_Arrays has the following
declaration:
generic
type Real is digits <>;
package Ada.Numerics.Generic_Real_Arrays is
pragma Pure(Generic_Real_Arrays);
-- Types
type Real_Vector is array (Integer range <>) of Real'Base;
type Real_Matrix is array (Integer range <>, Integer range <>) of Real'Base;
-- Subprograms for Real_Vector Types
-- Real_Vector arithmetic operations
function "+" (Right : Real_Vector) return Real_Vector;
function "-" (Right : Real_Vector) return Real_Vector;
function "abs" (Right : Real_Vector) return Real_Vector;
function "+" (Left, Right : Real_Vector) return Real_Vector;
function "-" (Left, Right : Real_Vector) return Real_Vector;
function "*" (Left, Right : Real_Vector) return Real_Vector;
function "/" (Left, Right : Real_Vector) return Real_Vector;
function "**" (Left : Real_Vector;
Right : Integer) return Real_Vector;
function "*" (Left, Right : Real_Vector) return Real'Base;
-- Real_Vector scaling operations
function "*" (Left : Real'Base; Right : Real_Vector) return Real_Vector;
function "*" (Left : Real_Vector; Right : Real'Base) return Real_Vector;
function "/" (Left : Real_Vector; Right : Real'Base) return Real_Vector;
-- Other Real_Vector operations
function Unit_Vector (Index : Integer;
Order : Positive;
First : Integer := 1) return Real_Vector;
-- Subprograms for Real_Matrix Types
-- Real_Matrix arithmetic operations
function "+" (Right : Real_Matrix) return Real_Matrix;
function "-" (Right : Real_Matrix) return Real_Matrix;
function "abs" (Right : Real_Matrix) return Real_Matrix;
function Transpose (X : Real_Matrix) return Real_Matrix;
function "+" (Left, Right : Real_Matrix) return Real_Matrix;
function "-" (Left, Right : Real_Matrix) return Real_Matrix;
function "*" (Left, Right : Real_Matrix) return Real_Matrix;
function "*" (Left, Right : Real_Vector) return Real_Matrix;
function "*" (Left : Real_Vector; Right : Real_Matrix) return Real_Vector;
function "*" (Left : Real_Matrix; Right : Real_Vector) return Real_Vector;
-- Real_Matrix scaling operations
function "*" (Left : Real'Base; Right : Real_Matrix) return Real_Matrix;
function "*" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix;
function "/" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix;
-- Other Real_Matrix operations
function Identity_Matrix (Order : Positive;
First_1, First_2 : Integer := 1) return Real_Matrix;
end Ada.Numerics.Generic_Real_Arrays;
Two types are defined and exported by Ada.Numerics.Generic_Real_Arrays. The
composite type Real_Vector is provided to represent a vector with components of
type Real; it is defined as an unconstrained, one-dimensional array with an
index of type Integer. The composite type Real_Matrix is provided to represent
a matrix with components of type Real; it is defined as an unconstrained,
two-dimensional array with indices of type Integer.
?? maybe indexes ??
The effect of the various functions is as described below. In most cases the
functions are described in terms of corresponding scalar operations of the type
Real; any exception raised by those operations is propagated by the array
operation. Moreover the accuracy of the result for each individual component is
as defined for the scalar operation unless stated otherwise.
function "+" (Right : Real_Vector) return Real_Vector;
function "-" (Right : Real_Vector) return Real_Vector;
function "abs" (Right : Real_Vector) return Real_Vector;
Each operation returns the result of applying the corresponding operation of
the type Real to each component of Right. These are the standard mathematical
operations for vector identity, negation and absolute value respectively. The
bounds of the result are those of Right.
function "+" (Left, Right : Real_Vector) return Real_Vector;
function "-" (Left, Right : Real_Vector) return Real_Vector;
function "*" (Left, Right : Real_Vector) return Real_Vector;
function "/" (Left, Right : Real_Vector) return Real_Vector;
Each operation returns the result of applying the corresponding operation of
the type Real to each component of Left and the matching component of Right.
These are the standard mathematical operations for vector addition,
subtraction, multiplication and division respectively. The bounds of the result
are those of the left operand. The exception Constraint_Error is raised if
Left'Length is not equal to Right'Length.
function "**" (Left : Real_Vector; Right : Integer) return Real_Vector;
This operation returns the result of applying the corresponding operation "**"
of the type Real with integer power Right to each component of Left. The bounds
of the result are those of the left operand.
function "*" (Left, Right : Real_Vector) return Real'Base;
This operation returns the inner (dot) product of Left and Right. The exception
Constraint_Error is raised if Left'Length is not equal to Right'Length. This
operation involves an inner product; an accuracy requirement is not specified.
Constraint_Error is raised if an intermediate result is outside the range of
Real'Base even though the mathematical final result would not be.
function "*" (Left : Real'Base; Right : Real_Vector) return Real_Vector;
This operation returns the result of multiplying each component of Right by the
scalar Left using the "*" operation of the type Real. This is the standard
mathematical operation for scaling a vector Right by a real number Left. The
bounds of the result are those of the right operand.
function "*" (Left : Real_Vector; Right : Real'Base) return Real_Vector;
function "/" (Left : Real_Vector; Right : Real'Base) return Real_Vector;
Each operation returns the result of applying the corresponding operation of
the type Real to each component of Left and to the scalar Right. These are
standard mathematical operations for scaling a vector Left by a real number
Right. The bounds of the result are those of the left operand.
function Unit_Vector (Index : Integer;
Order : Positive;
First : Integer := 1) return Real_Vector;
This function returns a "unit vector" with Order components and a lower bound
of First. All components are set to 0.0 except for the Index component which is
set to 1.0. The exception Constraint_Error is raised if Index < First, Index >
First + Order - 1 or if First + Order - 1 > Integer'Last. This function is
exact.
function "+" (Right : Real_Matrix) return Real_Matrix;
function "-" (Right : Real_Matrix) return Real_Matrix;
function "abs" (Right : Real_Matrix) return Real_Matrix;
Each operation returns the result of applying the corresponding operation of
the type Real to each component of Right. These are the standard mathematical
operations for matrix identity, negation and absolute value respectively. The
bounds of the result are those of Right.
function Transpose (X : Real_Matrix) return Real_Matrix;
This function returns the transpose of a matrix X. The index ranges of the
result are X'Range(2) and X'Range(1) (first and second index respectively).
This function is exact.
function "+" (Left, Right : Real_Matrix) return Real_Matrix;
function "-" (Left, Right : Real_Matrix) return Real_Matrix;
Each operation returns the result of applying the corresponding operation of
type Real to each component of Left and the matching component of Right. These
are also the standard mathematical operations for matrix addition and
subtraction. The bounds of the result are those of Left. The exception
Constraint_Error is raised if Left'Length(1) is not equal to Right'Length(1) or
Left'Length(2) is not equal to Right'Length(2).
function "*" (Left, Right : Real_Matrix) return Real_Matrix;
This operation provides the standard mathematical operation for matrix
multiplication. The index ranges of the result are Left'Range(1) and
Right'Range(2) (first and second index respectively). The exception
Constraint_Error is raised if Left'Length(2) is not equal to Right'Length(1).
This operation involves an inner product; an accuracy requirement is not
specified. Constraint_Error is raised if an intermediate result is outside the
range of Real'Base even though the mathematical final result would not be.
function "*" (Left, Right : Real_Vector) return Real_Matrix;
This operation provides the standard mathematical operation for multiplication
of a (column) vector Left by a (row) vector Right. The index ranges of the
matrix result are Left'Range and Right'Range (first and second index
respectively).
function "*" (Left : Real_Vector; Right : Real_Matrix) return Real_Vector;
This operation provides the standard mathematical operation for multiplication
of a (row) vector Left by a matrix Right. The index range of the (row) vector
result is Right'Range(2). The exception Constraint_Error is raised if
Left'Length is not equal to Right'Length(1). This operation involves an inner
product; an accuracy requirement is not specified. Constraint_Error is raised
if an intermediate result is outside the range of Real'Base even though the
mathematical final result would not be.
function "*" (Left : Real_Matrix; Right : Real_Vector) return Real_Vector;
This operation provides the standard mathematical operation for multiplication
of a matrix Left by a (column) vector Right. The index range of the (column)
vector result is Left'Range(1). The exception Constraint_Error is raised if
Left'Length(2) is not equal to Right'Length. This operation involves an inner
product; an accuracy requirement is not specified. Constraint_Error is raised
if an intermediate result is outside the range of Real'Base even though the
mathematical final result would not be.
function "*" (Left : Real'Base; Right : Real_Matrix) return Real_Matrix;
This operation returns the result of multiplying each component of Right by the
scalar Left using the "*" operation of the type Real. This is the standard
mathematical operation for scaling a matrix Right by a real number Left. The
index ranges of the matrix result are those of Right.
function "*" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix;
function "/" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix;
Each operation returns the result of applying the corresponding operation of
the type Real to each component of Left and to the scalar Right. These are
standard mathematical operations for scaling a matrix Left by a real number
Right. The index ranges of the matrix result are those of Left.
function Identity_Matrix (Order : Positive;
First_1, First_2 : Integer := 1) return Real_Matrix;
This function returns a square "identity matrix" with Order**2 components and
lower bounds of First_1 and First_2 (for the first and second index ranges
respectively). All components are set to 0.0 except for the main diagonal,
whose components are set to 1.0. The exception Constraint_Error is raised if
First_1 + Order - 1 > Integer'Last or First_2 + Order - 1 > Integer'Last. This
function is exact.
G.3.2 Complex Vectors and Matrices
The generic library package Numerics.Generic_Complex_Arrays has the following
declaration:
with Ada.Numerics.Generic_Real_Arrays, Ada.Numerics.Generic_Complex_Types;
generic
with package Real_Arrays is new Ada.Numerics.Generic_Real_Arrays (<>);
use Real_Arrays;
with package Complex_Types is new Ada.Numerics.Generic_Complex_Types (Real);
use Complex_Types;
package Ada.Numerics.Generic_Complex_Arrays is
pragma Pure(Generic_Complex_Arrays);
-- Types
type Complex_Vector is array (Integer range <>) of Complex;
type Complex_Matrix is array (Integer range <>,
Integer range <>) of Complex;
-- Subprograms for Complex_Vector types
-- Complex_Vector selection, conversion and composition operations
function Re (X : Complex_Vector) return Real_Vector;
function Im (X : Complex_Vector) return Real_Vector;
procedure Set_Re (X : in out Complex_Vector;
Re : in Real_Vector);
procedure Set_Im (X : in out Complex_Vector;
Im : in Real_Vector);
function Compose_From_Cartesian (Re : Real_Vector) return Complex_Vector;
function Compose_From_Cartesian (Re, Im : Real_Vector) return Complex_Vector;
function Modulus (X : Complex_Vector) return Real_Vector;
function "abs" (Right : Complex_Vector) return Real_Vector renames Modulus;
function Argument (X : Complex_Vector) return Real_Vector;
function Argument (X : Complex_Vector;
Cycle : Real'Base) return Real_Vector;
function Compose_From_Polar (Modulus, Argument : Real_Vector)
return Complex_Vector;
function Compose_From_Polar (Modulus, Argument : Real_Vector;
Cycle : Real'Base)
return Complex_Vector;
-- Complex_Vector arithmetic operations
function "+" (Right : Complex_Vector) return Complex_Vector;
function "-" (Right : Complex_Vector) return Complex_Vector;
function Conjugate (X : Complex_Vector) return Complex_Vector;
function "+" (Left, Right : Complex_Vector) return Complex_Vector;
function "-" (Left, Right : Complex_Vector) return Complex_Vector;
function "*" (Left, Right : Complex_Vector) return Complex_Vector;
function "/" (Left, Right : Complex_Vector) return Complex_Vector;
function "**" (Left : Complex_Vector;
Right : Integer) return Complex_Vector;
function "*" (Left, Right : Complex_Vector) return Complex;
-- Mixed Real_Vector and Complex_Vector arithmetic operations
function "+" (Left : Real_Vector;
Right : Complex_Vector) return Complex_Vector;
function "+" (Left : Complex_Vector;
Right : Real_Vector) return Complex_Vector;
function "-" (Left : Real_Vector;
Right : Complex_Vector) return Complex_Vector;
function "-" (Left : Complex_Vector;
Right : Real_Vector) return Complex_Vector;
function "*" (Left : Real_Vector;
Right : Complex_Vector) return Complex_Vector;
function "*" (Left : Complex_Vector;
Right : Real_Vector) return Complex_Vector;
function "/" (Left : Real_Vector;
Right : Complex_Vector) return Complex_Vector;
function "/" (Left : Complex_Vector;
Right : Real_Vector) return Complex_Vector;
function "*" (Left : Real_Vector; Right : Complex_Vector) return Complex;
function "*" (Left : Complex_Vector; Right : Real_Vector) return Complex;
-- Complex_Vector scaling operations
function "*" (Left : Complex;
Right : Complex_Vector) return Complex_Vector;
function "*" (Left : Complex_Vector;
Right : Complex) return Complex_Vector;
function "/" (Left : Complex_Vector;
Right : Complex) return Complex_Vector;
function "*" (Left : Real'Base;
Right : Complex_Vector) return Complex_Vector;
function "*" (Left : Complex_Vector;
Right : Real'Base) return Complex_Vector;
function "/" (Left : Complex_Vector;
Right : Real'Base) return Complex_Vector;
-- Other Complex_Vector operations
function Unit_Vector (Index : Integer;
Order : Positive;
First : Integer := 1) return Complex_Vector;
-- Subprograms for Complex_Matrix Types
-- Complex_Matrix selection, conversion and composition operations
function Re (X : Complex_Matrix) return Real_Matrix;
function Im (X : Complex_Matrix) return Real_Matrix;
procedure Set_Re (X : in out Complex_Matrix;
Re : in Real_Matrix);
procedure Set_Im (X : in out Complex_Matrix;
Im : in Real_Matrix);
function Compose_From_Cartesian (Re : Real_Matrix) return Complex_Matrix;
function Compose_From_Cartesian (Re, Im : Real_Matrix) return Complex_Matrix;
function Modulus (X : Complex_Matrix) return Real_Matrix;
function "abs" (Right : Complex_Matrix) return Real_Matrix renames Modulus;
function Argument (X : Complex_Matrix) return Real_Matrix;
function Argument (X : Complex_Matrix;
Cycle : Real'Base) return Real_Matrix;
function Compose_From_Polar (Modulus, Argument : Real_Matrix)
return Complex_Matrix;
function Compose_From_Polar (Modulus, Argument : Real_Matrix;
Cycle : Real'Base)
return Complex_Matrix;
-- Complex_Matrix arithmetic operations
function "+" (Right : Complex_Matrix) return Complex_Matrix;
function "-" (Right : Complex_Matrix) return Complex_Matrix;
function Conjugate (X : Complex_Matrix) return Complex_Matrix;
function Transpose (X : Complex_Matrix) return Complex_Matrix;
function "+" (Left, Right : Complex_Matrix) return Complex_Matrix;
function "-" (Left, Right : Complex_Matrix) return Complex_Matrix;
function "*" (Left, Right : Complex_Matrix) return Complex_Matrix;
function "*" (Left, Right : Complex_Vector) return Complex_Matrix;
function "*" (Left : Complex_Vector;
Right : Complex_Matrix) return Complex_Vector;
function "*" (Left : Complex_Matrix;
Right : Complex_Vector) return Complex_Vector;
-- Mixed Real_Matrix and Complex_Matrix arithmetic operations
function "+" (Left : Real_Matrix;
Right : Complex_Matrix) return Complex_Matrix;
function "+" (Left : Complex_Matrix;
Right : Real_Matrix) return Complex_Matrix;
function "-" (Left : Real_Matrix;
Right : Complex_Matrix) return Complex_Matrix;
function "-" (Left : Complex_Matrix;
Right : Real_Matrix) return Complex_Matrix;
function "*" (Left : Real_Matrix;
Right : Complex_Matrix) return Complex_Matrix;
function "*" (Left : Complex_Matrix;
Right : Real_Matrix) return Complex_Matrix;
function "*" (Left : Real_Vector;
Right : Complex_Vector) return Complex_Matrix;
function "*" (Left : Complex_Vector;
Right : Real_Vector) return Complex_Matrix;
function "*" (Left : Real_Vector;
Right : Complex_Matrix) return Complex_Vector;
function "*" (Left : Complex_Vector;
Right : Real_Matrix) return Complex_Vector;
function "*" (Left : Real_Matrix;
Right : Complex_Vector) return Complex_Vector;
function "*" (Left : Complex_Matrix;
Right : Real_Vector) return Complex_Vector;
-- Complex_Matrix scaling operations
function "*" (Left : Complex;
Right : Complex_Matrix) return Complex_Matrix;
function "*" (Left : Complex_Matrix;
Right : Complex) return Complex_Matrix;
function "/" (Left : Complex_Matrix;
Right : Complex) return Complex_Matrix;
function "*" (Left : Real'Base;
Right : Complex_Matrix) return Complex_Matrix;
function "*" (Left : Complex_Matrix;
Right : Real'Base) return Complex_Matrix;
function "/" (Left : Complex_Matrix;
Right : Real'Base) return Complex_Matrix;
-- Other Complex_Matrix operations
function Identity_Matrix (Order : Positive;
First_1, First_2 : Integer := 1)
return Complex_Matrix;
end Ada.Numerics.Generic_Complex_Arrays;
To be concluded
!example
To be done
!discussion
To be done
!ACATS Test
ACATS test(s) need to be created.
!appendix
****************************************************************
Recommendation on ISO/IEC 13813 from the UK
The standard ISO/IEC 13813 entitled generic packages of real and complex type
declarations and basic operations for Ada (including vector and matrix types)
will soon be up for review. This note reviews the background to the development
of the standard and makes a recommendation that the standard be revised.
Background
The Numerics Working Group of WG9 met many times during the period when Ada 95
was being designed and produced a number of standards. They were faced with the
problem of whether to produce standards based on Ada 83 (87 in ISO terms) or
whether to base them on Ada 95 or subsume them into Ada 95. One dilemma was of
course that although Ada 95 was on the way nevertheless Ada 83 was expected to
continue in use for many years.
The standards are
11430: Generic package of elementary functions for Ada.
11729: Generic package of primitive functions for Ada.
13813: Generic packages of real and complex type declarations and basic
operations for Ada (including vector and matrix types).
13814: Generic package of complex elementary functions for Ada.
11430 and 11729 are mentioned for completeness. They were published in 1994.
They were based entirely on Ada 83 and their facilities are provided in the Ada
95 core language. The elementary functions, 11430, became the package
Ada.Numerics.Generic_Elementary_Functions and the primitive functions, 11729,
became the various attributes such as 'Floor and 'Ceiling, and 'Exponent and
'Fraction. These two standards were withdrawn recently and need no further
mention.
The other two standards, 13813 and 13814, were published in 1998 and will soon
be up for review at the end of their five year period. Three possible fates can
befall a standard when it is reviewed. It can be withdrawn, revised or
confirmed.
In the case of 13814, the functionality is all incorporated into the Numerics
Annex of Ada 95 as the package
Ada.Numerics.Generic_Complex_Elementary_Functions. There are a few changes in
presentation because the Ada 95 package uses the generic package parameter
feature which of course did not exist in Ada 83. Nevertheless there seems
little point in continuing with 13814 and so at the Leuven meeting of WG9 it
was agreed to recommend that it be withdrawn.
However, the situation regarding 13813 is not so clear. Some of its
functionality is included in Ada 95 but quite a lot is not. The topics covered
are (1) a complex types package including various complex arithmetic
operations, (2) a real arrays package covering both vectors and matrices, (3) a
complex arrays package covering both vectors and matrices, (4) a complex
input-output package.
The complex types package (1) became the package
Ada.Numerics.Generic_Complex_Types and the input-output package (4) became
Ada.Text_IO.Complex_IO. However, the array packages, both real and complex,
were not incorporated into the Ada 95 standard.
At the Leuven meeting, it was agreed that 13813 should not be withdrawn without
further study. The UK was asked to study whether small or large changes are
required in 13813 and to report back. The Ada Rapporteur Group would then
decide whether the functionality should be included in a future revision or
amendment to Ada 95.
This is the report from the UK.
Recommendation
It is recommended that 13813 be revised so that it only contains the
functionality not included in Ada 95.
The revised standard should contain two generic packages namely
Ada.Numerics.Generic_Real_Arrays and Ada.Numerics.Generic_Complex_Arrays.
There should also be standard non-generic packages corresponding to the
predefined types such as Float in an analogous manner to the standard packages
such as Ada.Numerics.Complex_Types and Ada.Numerics.Long_Complex_Types for
Float and Long_Float respectively.
The text of the Ada specifications of the two generic packages should be
essentially as given in the nonnormative Annex G of the existing standard
13813. (This Annex illustrates how the existing standard packages might be
rewritten using Ada 95. There is an error regarding the formal package
parameters which has been corrected in the revised text.)
There is an important issue regarding what should happen if there is a mismatch
in the array lengths of the parameters in a number of the subprograms provided
by the packages. For example if
function "+" (Left, Right: Real_Vector) return Real_Vector
be called with parameters such that Left'Length /= Right'Length.
The existing standard raises the exception Array_Index_Error which is declared
alone in a package Array_Exceptions. The nonnormative Annex G shows this
exception incorporated into the package Ada.Numerics thereby producing an
incompatibility with the existing definition of Ada.Numerics.
We considered four possibilities regarding this exception
1) Add Array_Index_Error to Ada.Numerics as in Annex G.
2) Place Array_Index_Error in a new child package such as Ada.Numerics.Arrays.
3) Eliminate Array_Index_Error and raise Constraint_Error instead.
4) State that the behaviour with mismatched arrays is implementation-defined.
We concluded that
Option (1) is undesirable because of incompatibility.
Option (2) is feasible but one ought then to place the generic packages
themselves into this package so that they become
Ada.Numerics.Arrays.Generic_Real_Arrays and
Ada.Numerics.Arrays.Generic_Complex_Arrays. This nesting is considered
cumbersome.
Option(3) gives the same behaviour as similar mismatching on predefined
operations and although losing some specificacity has practical simplicity.
Option (4) is disliked since gratuitous implementation-defined
behaviour should be avoided.
We therefore recommend Option (3) that Constraint_Error be raised on
mismatching of parameters.
If the Ada95 standard itself be revised at some later date then consideration
should be given to incorporating the functionality of the revised 13813 into
the Numerics Annex.
Proposed text
The proposed normative text of the revised standard is distributed separately
as N404, Working Draft, Revision of ISO/IEC 13813. Note that the non-normative
rationale section remains to be completed and that consequently the
bibliography might need alterations to match.
Acknowledgment
We acknowledge the valuable assistance of Donald Sando, the editor of the
original standard, in the preparation of this recommendation.
****************************************************************