G.1.1 Complex Types
Static Semantics
The generic library 
package Numerics.Generic_Complex_Types has the following declaration: 
generic
   type Real 
is digits <>;
package Ada.Numerics.Generic_Complex_Types 
is
   pragma Pure(Generic_Complex_Types);
 
   type Complex 
is
      record
         Re, Im : Real'Base;
      
end record;
 
   type Imaginary 
is private;
   
pragma Preelaborable_Initialization(Imaginary);
 
   i : 
constant Imaginary;
   
j : 
constant Imaginary;
 
   function Re (X : Complex)   
return Real'Base;
   
function Im (X : Complex)   
return Real'Base;
   
function Im (X : Imaginary) 
return Real'Base;
 
   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);
 
   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;
 
   function Modulus (X     : Complex) 
return Real'Base;
   
function "
abs"   (Right : Complex) 
return Real'Base 
renames Modulus;
 
   function Argument (X     : Complex)   
return Real'Base;
   
function Argument (X     : Complex;
                      Cycle : Real'Base) 
return Real'Base;
 
   function Compose_From_Polar (Modulus, Argument        : Real'Base)
      
return Complex;
   
function Compose_From_Polar (Modulus, Argument, Cycle : Real'Base)
      
return Complex;
 
   function "+"       (Right : Complex) 
return Complex;
   
function "-"       (Right : Complex) 
return Complex;
   
function Conjugate (X     : Complex) 
return Complex;
 
   function "+" (Left, Right : Complex) return Complex;
   function "-" (Left, Right : Complex) return Complex;
   function "*" (Left, Right : Complex) return Complex;
   function "/" (Left, Right : Complex) return Complex;
   function "**" (Left : Complex; Right : Integer) return Complex;
   function "+"       (Right : Imaginary) 
return Imaginary;
   
function "-"       (Right : Imaginary) 
return Imaginary;
   
function Conjugate (X     : Imaginary) 
return Imaginary 
renames "-";
   
function "
abs"     (Right : Imaginary) 
return Real'Base;
 
   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;
   function "**" (Left : Imaginary; Right : Integer) return Complex;
   function "<"  (Left, Right : Imaginary) return Boolean;
   function "<=" (Left, Right : Imaginary) return Boolean;
   function ">"  (Left, Right : Imaginary) return Boolean;
   function ">=" (Left, Right : Imaginary) return Boolean;
   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;
   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;
   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;
private
   type Imaginary is new Real'Base;
   i : constant Imaginary := 1.0;
   j : constant Imaginary := 1.0;
end Ada.Numerics.Generic_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. 
 
 Complex is a visible type with Cartesian components. 
Imaginary is a private type; its full type is derived 
from Real'Base. 
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: 
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.
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.
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. 
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.
The computed results 
of the mathematically multivalued functions are rendered single-valued 
by the following conventions, which are meant to imply the principal 
branch: 
The result of the Modulus function is nonnegative.
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 
π (resp., –π) when the 
sign of the imaginary component of X is positive (resp., negative), if 
Real'Signed_Zeros is True;
π, if Real'Signed_Zeros is False. 
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
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.
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
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. 
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: 
 
The results of the Re, Im, and Compose_From_Cartesian 
functions are exact.
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. 
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.
The real component of the result of the Conjugate 
function for the complex type is exact.
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. 
When the value of the parameter Modulus is zero, 
the Compose_From_Polar function yields a result of zero.
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.
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. 
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.
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.
 
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
The nongeneric equivalent packages may, but need 
not, be actual instantiations of the generic package for the appropriate 
predefined type.
 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; 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
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. 
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.
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. 
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe