Contents Index Search Previous Next
G.1.1 Complex Types
Static Semantics
1
The generic library
package Numerics.Generic_Complex_Types has the following declaration:
2/1
{8652/0020}
generic
type Real is digits <>;
package Ada.Numerics.Generic_Complex_Types is
pragma 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/1
{
8652/0020}
{Ada.Numerics.Complex_Types} The
library package Numerics.Complex_Types
is declared pure and 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.
25.a
Reason: The nongeneric
equivalents are provided to allow the programmer to construct simple
mathematical applications without being required to understand and use
generics.
25.b
Reason: The nongeneric
equivalents all export the types Complex and Imaginary and the constants
i and j (rather than uniquely named types and constants, such as Short_Complex,
Long_Complex, etc.) to preserve their equivalence to actual instantiations
of the generic package and to allow the programmer to change the precision
of an application globally by changing a single context clause.
26
[Complex is a visible type with cartesian components.]
26.a
Reason: The cartesian
representation is far more common than the polar representation, in practice.
The accuracy of the results of the complex arithmetic operations and
of the complex elementary functions is dependent on the representation;
thus, implementers need to know that representation. The type is visible
so that complex ``literals'' can be written in aggregate notation, if
desired.
27
[Imaginary is a private type; its full type is
derived from Real'Base.]
27.a
Reason:
The Imaginary type and the constants i and j are provided for two
reasons:
27.b
- They allow complex
``literals'' to be written in the alternate form of a + b*i
(or a + b*j), if desired. Of course, in some contexts the
sum will need to be parenthesized.
27.c
- When an Ada binding
to IEC 559:1989 that provides (signed) infinities as the result of operations
that overflow becomes available, it will be important to allow arithmetic
between pure-imaginary and complex operands without requiring the former
to be represented as (or promoted to) complex values with a real component
of zero. For example, the multiplication of a + b*i by
d*i should yield -b· d + a·
d*i, but if one cannot avoid representing the pure-imaginary value
d*i as the complex value 0.0 + d*i, then a NaN ("Not-a-Number")
could be produced as the result of multiplying a by 0.0 (e.g.,
when a is infinite); the NaN could later trigger an exception.
Providing the Imaginary type and overloadings of the arithmetic operators
for mixtures of Imaginary and Complex operands gives the programmer the
same control over avoiding premature coercion of pure-imaginary values
to complex as is already provided for pure-real values.
27.d
Reason:
The Imaginary type is private, rather than being visibly derived
from Real'Base, for two reasons:
27.e
- to preclude implicit
conversions of real literals to the Imaginary type (such implicit conversions
would make many common arithmetic expressions ambiguous); and
27.f
- to suppress the
implicit derivation of the multiplication, division, and absolute value
operators with Imaginary operands and an Imaginary result (the result
type would be incorrect).
27.g
Reason: The base subtype
Real'Base is used for the component type of Complex, the parent type
of Imaginary, and the parameter and result types of some of the subprograms
to maximize the chances of being able to pass meaningful values into
the subprograms and receive meaningful results back. The generic formal
parameter Real therefore plays only one role, that of providing the precision
to be maintained in complex arithmetic calculations. Thus, the subprograms
in Numerics.Generic_Complex_Types share with those in Numerics.Generic_Elementary_Functions,
and indeed even with the predefined arithmetic operations (see 4.5),
the property of being free of range checks on input and output, i.e.,
of being able to exploit the base range of the relevant floating point
type fully. As a result, the user loses the ability to impose application-oriented
bounds on the range of values that the components of a complex variable
can acquire; however, it can be argued that few, if any, applications
have a naturally square domain (as opposed to a circular domain) anyway.
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:
28.a
Reason: The middle case
can be understood by considering the parameter of pure-imaginary type
to represent a complex value with a zero real part.
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
{Division_Check [partial]}
{check, language-defined (Division_Check)}
{Constraint_Error (raised by failure
of run-time check)} 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.
{unspecified [partial]}
[Constraint_Error can also be raised when a finite
result overflows (see
G.2.6).]
40.a
Discussion: It is anticipated
that an Ada binding to IEC 559:1989 will be developed in the future.
As part of such a binding, the Machine_Overflows attribute of a conformant
floating point type will be specified to yield False, which will permit
implementations of the complex arithmetic operations to deliver results
with an infinite component (and set the overflow flag defined by the
binding) instead of raising Constraint_Error in overflow situations,
when traps are disabled. Similarly, it is appropriate for the complex
arithmetic operations to deliver results with infinite components (and
set the zero-divide flag defined by the binding) instead of raising Constraint_Error
in the situations defined above, when traps are disabled. Finally, such
a binding should also specify the behavior of the complex arithmetic
operations, when sensible, given operands with infinite components.
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.
41.a
Implementation Note: Implementations
of Numerics.Generic_Complex_Types written in Ada should therefore avoid
declaring local variables of subtype Real; the subtype Real'Base should
be used instead.
42
{prescribed
result (for the evaluation of a complex arithmetic operation)}
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.
44.a
Ramification: The result
of the addition operator is exact when one of its operands is of real
type and the other is of pure-imaginary type. In this particular case,
the operator is analogous to the Compose_From_Cartesian function; it
performs no arithmetic.
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.
47.a
Discussion: Argument(X
+ i*Y) is analogous to EF.Arctan(Y, X), where EF is an
appropriate instance of Numerics.Generic_Elementary_Functions, except
when X and Y are both zero, in which case the former yields the value
zero while the latter raises Numerics.Argument_Error.
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.
53.a
Implementation defined: The
sign of a zero result (or a component thereof) from any operator or function
in Numerics.Generic_Complex_Types, 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/1
{
8652/0091}
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.
Wording Changes from Ada 83
58.a
The
semantics of Numerics.Generic_Complex_Types differs from Generic_Complex_Types
as defined in ISO/IEC CD 13813 (for Ada 83) in the following ways:
58.b
- The generic package
is a child of the package defining the Argument_Error exception.
58.c
- The nongeneric
equivalents export types and constants with the same names as those exported
by the generic package, rather than with names unique to the package.
58.d
- Implementations
are not allowed to impose an optional restriction that the generic actual
parameter associated with Real be unconstrained. (In view of the ability
to declare variables of subtype Real'Base in implementations of Numerics.Generic_Complex_Types,
this flexibility is no longer needed.)
58.e
- The dependence
of the Argument function on the sign of a zero parameter component is
tied to the value of Real'Signed_Zeros.
58.f
- Conformance to
accuracy requirements is conditional.
Contents Index Search Previous Next Legal