Static Semantics
- (1)
- The generic library package Numerics.Generic_Complex_Types has the
following declaration:
(2)
generic
type Real is digits <>;
package Ada.Numerics.Generic_Complex_Types is
pragma Pure(Generic_Complex_Types);
(3)
type Complex is
record
Re, Im : Real'Base;
end record;
(4)
type Imaginary is private;
(5)
i : constant Imaginary;
j : constant Imaginary;
(6)
function Re (X : Complex) return Real'Base;
function Im (X : Complex) return Real'Base;
function Im (X : Imaginary) return Real'Base;
(7)
procedure Set_Re (X : in out Complex;
Re : in Real'Base);
procedure Set_Im (X : in out Complex;
Im : in Real'Base);
procedure Set_Im (X : out Imaginary;
Im : in Real'Base);
(8)
function Compose_From_Cartesian (Re, Im : Real'Base) return Complex;
function Compose_From_Cartesian (Re : Real'Base) return Complex;
function Compose_From_Cartesian (Im : Imaginary) return Complex;
(9)
function Modulus (X : Complex) return Real'Base;
function "abs" (Right : Complex) return Real'Base renames Modulus;
(10)
function Argument (X : Complex) return Real'Base;
function Argument (X : Complex;
Cycle : Real'Base) return Real'Base;
(11)
function Compose_From_Polar (Modulus, Argument : Real'Base)
return Complex;
function Compose_From_Polar (Modulus, Argument, Cycle : Real'Base)
return Complex;
(12)
function "+" (Right : Complex) return Complex;
function "-" (Right : Complex) return Complex;
function Conjugate (X : Complex) return Complex;
(13)
function "+" (Left, Right : Complex) return Complex;
function "-" (Left, Right : Complex) return Complex;
function "*" (Left, Right : Complex) return Complex;
function "/" (Left, Right : Complex) return Complex;
(14)
function "**" (Left : Complex; Right : Integer) return Complex;
(15)
function "+" (Right : Imaginary) return Imaginary;
function "-" (Right : Imaginary) return Imaginary;
function Conjugate (X : Imaginary) return Imaginary renames "-";
function "abs" (Right : Imaginary) return Real'Base;
(16)
function "+" (Left, Right : Imaginary) return Imaginary;
function "-" (Left, Right : Imaginary) return Imaginary;
function "*" (Left, Right : Imaginary) return Real'Base;
function "/" (Left, Right : Imaginary) return Real'Base;
(17)
function "**" (Left : Imaginary; Right : Integer) return Complex;
(18)
function "<" (Left, Right : Imaginary) return Boolean;
function "<=" (Left, Right : Imaginary) return Boolean;
function ">" (Left, Right : Imaginary) return Boolean;
function ">=" (Left, Right : Imaginary) return Boolean;
(19)
function "+" (Left : Complex; Right : Real'Base) return Complex;
function "+" (Left : Real'Base; Right : Complex) return Complex;
function "-" (Left : Complex; Right : Real'Base) return Complex;
function "-" (Left : Real'Base; Right : Complex) return Complex;
function "*" (Left : Complex; Right : Real'Base) return Complex;
function "*" (Left : Real'Base; Right : Complex) return Complex;
function "/" (Left : Complex; Right : Real'Base) return Complex;
function "/" (Left : Real'Base; Right : Complex) return Complex;
(20)
function "+" (Left : Complex; Right : Imaginary) return Complex;
function "+" (Left : Imaginary; Right : Complex) return Complex;
function "-" (Left : Complex; Right : Imaginary) return Complex;
function "-" (Left : Imaginary; Right : Complex) return Complex;
function "*" (Left : Complex; Right : Imaginary) return Complex;
function "*" (Left : Imaginary; Right : Complex) return Complex;
function "/" (Left : Complex; Right : Imaginary) return Complex;
function "/" (Left : Imaginary; Right : Complex) return Complex;
(21)
function "+" (Left : Imaginary; Right : Real'Base) return Complex;
function "+" (Left : Real'Base; Right : Imaginary) return Complex;
function "-" (Left : Imaginary; Right : Real'Base) return Complex;
function "-" (Left : Real'Base; Right : Imaginary) return Complex;
function "*" (Left : Imaginary; Right : Real'Base) return Imaginary;
function "*" (Left : Real'Base; Right : Imaginary) return Imaginary;
function "/" (Left : Imaginary; Right : Real'Base) return Imaginary;
function "/" (Left : Real'Base; Right : Imaginary) return Imaginary;
(22)
private
(23)
type Imaginary is new Real'Base;
i : constant Imaginary := 1.0;
j : constant Imaginary := 1.0;
(24)
end Ada.Numerics.Generic_Complex_Types;
- (25)
- The library package Numerics.Complex_Types defines the same types,
constants, and subprograms as Numerics.Generic_Complex_Types, except that the
predefined type Float is systematically substituted for Real'Base throughout.
Nongeneric equivalents of Numerics.Generic_Complex_Types for each of the
other predefined floating point types are defined similarly, with the names
Numerics.Short_Complex_Types, Numerics.Long_Complex_Types, etc.
- (26)
- Complex is a visible type with cartesian components.
- (27)
- Imaginary is a private type; its full type is derived from Real'Base.
- (28)
- The arithmetic operations and the Re, Im, Modulus, Argument, and
Conjugate functions have their usual mathematical meanings. When applied to
a parameter of pure-imaginary type, the ``imaginary-part'' function Im yields
the value of its parameter, as the corresponding real value. The remaining
subprograms have the following meanings:
- (29)
- The Set_Re and Set_Im procedures replace the designated component
of a complex parameter with the given real value; applied to a
parameter of pure-imaginary type, the Set_Im procedure replaces
the value of that parameter with the imaginary value
corresponding to the given real value.
- (30)
- The Compose_From_Cartesian function constructs a complex value
from the given real and imaginary components. If only one
component is given, the other component is implicitly zero.
- (31)
- The Compose_From_Polar function constructs a complex value from
the given modulus (radius) and argument (angle). When the value
of the parameter Modulus is positive (resp., negative), the
result is the complex value represented by the point in the
complex plane lying at a distance from the origin given by the
absolute value of Modulus and forming an angle measured
counterclockwise from the positive (resp., negative) real axis
given by the value of the parameter Argument.
- (32)
- When the Cycle parameter is specified, the result of the Argument
function and the parameter Argument of the Compose_From_Polar function are
measured in units such that a full cycle of revolution has the given value;
otherwise, they are measured in radians.
- (33)
- The computed results of the mathematically multivalued functions are
rendered single-valued by the following conventions, which are meant to imply
the principal branch:
- (34)
- The result of the Modulus function is nonnegative.
- (35)
- The result of the Argument function is in the quadrant containing
the point in the complex plane represented by the parameter
X. This may be any quadrant (I through IV); thus, the range of
the Argument function is approximately -Pi to Pi (-Cycle/2.0 to
Cycle/2.0, if the parameter Cycle is specified). When the point
represented by the parameter X lies on the negative real axis,
the result approximates
- (36)
- Pi (resp., -Pi) when the sign of the imaginary component
of X is positive (resp., negative), if Real'Signed_Zeros
is True;
- (37)
- Pi, if Real'Signed_Zeros is False.
- (38)
- Because a result lying on or near one of the axes may not be
exactly representable, the approximation inherent in computing
the result may place it in an adjacent quadrant, close to but on
the wrong side of the axis.
Dynamic Semantics
- (39)
- The exception Numerics.Argument_Error is raised by the Argument and
Compose_From_Polar functions with specified cycle, signaling a parameter
value outside the domain of the corresponding mathematical function, when the
value of the parameter Cycle is zero or negative.
- (40)
- The exception Constraint_Error is raised by the division operator when the
value of the right operand is zero, and by the exponentiation operator when
the value of the left operand is zero and the value of the exponent is negative,
provided that Real'Machine_Overflows is True; when Real'Machine_Overflows
is False, the result is unspecified. Constraint_Error can also be raised when
a finite result overflows (see G.2.6).
Implementation Requirements
- (41)
- In the implementation of Numerics.Generic_Complex_Types, the range of
intermediate values allowed during the calculation of a final result shall
not be affected by any range constraint of the subtype Real.
- (42)
- In the following cases, evaluation of a complex arithmetic operation
shall yield the prescribed result, provided that the preceding rules do not
call for an exception to be raised:
- (43)
- The results of the Re, Im, and Compose_From_Cartesian functions
are exact.
- (44)
- The real (resp., imaginary) component of the result of a binary
addition operator that yields a result of complex type is exact
when either of its operands is of pure-imaginary (resp., real)
type.
- (45)
- The real (resp., imaginary) component of the result of a binary
subtraction operator that yields a result of complex type is
exact when its right operand is of pure-imaginary (resp., real)
type.
- (46)
- The real component of the result of the Conjugate function for
the complex type is exact.
- (47)
- When the point in the complex plane represented by the parameter
X lies on the nonnegative real axis, the Argument function yields
a result of zero.
- (48)
- When the value of the parameter Modulus is zero, the Compose_From_Polar function yields a result of zero.
- (49)
- When the value of the parameter Argument is equal to a multiple
of the quarter cycle, the result of the Compose_From_Polar
function with specified cycle lies on one of the axes. In this
case, one of its components is zero, and the other has the
magnitude of the parameter Modulus.
- (50)
- Exponentiation by a zero exponent yields the value one.
Exponentiation by a unit exponent yields the value of the left
operand. Exponentiation of the value one yields the value one.
Exponentiation of the value zero yields the value zero, provided
that the exponent is nonzero. When the left operand is of
pure-imaginary type, one component of the result of the
exponentiation operator is zero.
- (51)
- When the result, or a result component, of any operator of
Numerics.Generic_Complex_Types has a mathematical definition in terms of a
single arithmetic or relational operation, that result or result component
exhibits the accuracy of the corresponding operation of the type Real.
- (52)
- Other accuracy requirements for the Modulus, Argument, and Compose_From_Polar
functions, and accuracy requirements for the multiplication of a pair of complex
operands or for division by a complex operand, all of which apply only in
the strict mode, are given in G.2.6.
- (53)
- The sign of a zero result or zero result component yielded by a complex
arithmetic operation or function is implementation defined when Real'Signed_Zeros is True.
Implementation Permissions
- (54)
- The nongeneric equivalent packages may, but need not, be actual
instantiations of the generic package for the appropriate predefined type.
- (55)
- Implementations may obtain the result of exponentiation of a complex or
pure-imaginary operand by repeated complex multiplication, with arbitrary
association of the factors and with a possible final complex reciprocation
(when the exponent is negative). Implementations are also permitted to
obtain the result of exponentiation of a complex operand, but not of a
pure-imaginary operand, by converting the left operand to a polar
representation; exponentiating the modulus by the given exponent; multiplying
the argument by the given exponent, when the exponent is positive, or
dividing the argument by the absolute value of the given exponent, when the
exponent is negative; and reconverting to a cartesian representation.
Because of this implementation freedom, no accuracy requirement is imposed on
complex exponentiation (except for the prescribed results given above, which
apply regardless of the implementation method chosen).
Implementation Advice
- (56)
- Because the usual mathematical meaning of multiplication of a complex
operand and a real operand is that of the scaling of both components of the
former by the latter, an implementation should not perform this operation by
first promoting the real operand to complex type and then performing a full
complex multiplication. In systems that, in the future, support an Ada
binding to IEC 559:1989, the latter technique will not generate the required
result when one of the components of the complex operand is infinite.
(Explicit multiplication of the infinite component by the zero component
obtained during promotion yields a NaN that propagates into the final
result.) Analogous advice applies in the case of multiplication of a complex
operand and a pure-imaginary operand, and in the case of division of a
complex operand by a real or pure-imaginary operand.
- (57)
- Likewise, because the usual mathematical meaning of addition of a
complex operand and a real operand is that the imaginary operand remains
unchanged, an implementation should not perform this operation by first
promoting the real operand to complex type and then performing a full complex
addition. In implementations in which the Signed_Zeros attribute of the
component type is True (and which therefore conform to IEC 559:1989 in regard
to the handling of the sign of zero in predefined arithmetic operations), the
latter technique will not generate the required result when the imaginary
component of the complex operand is a negatively signed zero. (Explicit
addition of the negative zero to the zero obtained during promotion yields a
positive zero.) Analogous advice applies in the case of addition of a
complex operand and a pure-imaginary operand, and in the case of subtraction
of a complex operand and a real or pure-imaginary operand.
- (58)
- Implementations in which Real'Signed_Zeros is True should attempt to
provide a rational treatment of the signs of zero results and result
components. As one example, the result of the Argument function should have
the sign of the imaginary component of the parameter X when the point
represented by that parameter lies on the positive real axis; as another, the
sign of the imaginary component of the Compose_From_Polar function should be
the same as (resp., the opposite of) that of the Argument parameter when that
parameter has a value of zero and the Modulus parameter has a nonnegative
(resp., negative) value.
-- Email comments, additions, corrections, gripes, kudos, etc. to:
Magnus Kempe -- Magnus.Kempe@di.epfl.ch
Copyright statement
Page last generated: 95-03-12