G.1.1 Complex Types
Static Semantics
1
The generic library 
package Numerics.Generic_Complex_Types has the following declaration: 
2/1
{
8652/0020} 
{
AI95-00126-01} 
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/2
{
AI95-00161-01} 
   
type Imaginary 
is private;
   pragma Preelaborable_Initialization(Imaginary); 
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} 
{
AI95-00126-01} 
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/2
 {
AI95-00434-01} 
[Complex is a visible type with 
Cartesian cartesian 
components.] 
 
26.a
Reason: The Cartesian 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 –π to π (–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
- π (resp., –π) when 
the sign of the imaginary component of X is positive (resp., negative), 
if Real'Signed_Zeros is True;
 
37
- π, 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/2
 {
8652/0091} 
{
AI95-00434-01} 
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 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. 
56.a/2
Implementation Advice: 
Mixed real and complex operations (as 
well as pure-imaginary and complex operations) should not be performed 
by converting the real (resp. pure-imaginary) operand to complex.
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. 
58.a.1/2
Implementation Advice: 
If Real'Signed_Zeros is true for Numerics.Generic_Complex_Types, 
a rational treatment of the signs of zero results and result components 
should be provided.
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. 
 
Extensions to Ada 95
58.g/2
{
AI95-00161-01} 
{extensions to Ada 95} Amendment 
Correction: Added a pragma Preelaborable_Initialization 
to type Imaginary, so that it can be used in preelaborated units. 
 
Wording Changes from Ada 95
58.h/2
{
8652/0020} 
{
AI95-00126-01} 
Corrigendum: Explicitly stated that the 
nongeneric equivalents of Generic_Complex_Types are pure.