10.8
Advanced concepts*
Base range
Clearly, a computer will not support different hardware formats for each floating point type such as digits6,digits7,digits8. The implementation will represent values of each type in a hardware format that can contain at least the values of the type, but possibly more. Similarly, an enumeration or integer type will be stored in a hardware format whose range of values may be significantly more than the minimum required.
§3.5
6 Thebase rangeof a scalar type is the range of finite values of the type that can be represented in every unconstrained object of the type; it is also the range supported at a minimum for intermediate values during the evaluation of expressions involving predefined operators of the type.
15 S’Base—S’Base denotes an unconstrained subtype of the type of S. This uncon- strained subtype is called thebase subtypeof the type.
Of course the base range is implementation-dependent, soS’Baseshould not normally be used in writing Ada programs. Base ranges are important in defining the language and in optimizing ma- chine code. Predefined arithmetical operators are defined §A.1(15–18) for the unconstrained type
Integer’Base, not for the constrained typeInteger. Range checks never apply to an unconstrained type. Consider:
N1, N2: Integer := 15_000; N3: Integer := (N1 + N2) / 2;
Suppose the implementation defines typeIntegerto have a 16-bit range, butInteger’Baseis defined to have a 32-bit range because all computation is performed in 32-bit registers. If "+" were defined on parameters of typeInteger, the addition would be required to raiseConstraint_Error. However, since the addition is performed on the unconstrained typeInteger’Base, no range check need be done until the assignment toN3andConstraint_Errorwill not be raised. You can also declare variables of the unconstrained type to explicitly hold intermediate values of a computation. Note that predefined Integer is constrained §3.5.4(11) to its base range while Float is uncon- strained §3.5.7(12).
10.8 Advanced concepts* 175
Complex numbers
Annex §G‘Numerics’ defines support for complex arithmetic including elementary functions and IO.
§G.1.1
2 generic
typeReal is digits<>;
packageAda.Numerics.Generic_Complex_Types is pragmaPure(Generic_Complex_Types); 3 typeComplex is record Re, Im : Real’Base; end record;
4 typeImaginaryis private; 5 i : constantImaginary;
j : constant Imaginary; 22 private
typeImaginaryis new Real’Base; 23 i : constantImaginary := 1.0;
j : constant Imaginary := 1.0;
24 endAda.Numerics.Generic_Complex_Types;
The reasonImaginaryis declared as a separate type is to allow expressions of the formR1 + I1*i. Since the type Complexis visible, you can create values of the type using ordinary aggregates such as(5.0, 6.3). The arithmetical operators are overloaded for all combinations of parameters of typesReal’Base,ComplexandImaginary.
Ada.Numerics.Complex_Typesis a predefined instantiation of the generic package for predefined
Float.
§G.1.2declares a generic package for complex elementary functions and §G.1.3declares a generic package for IO. These packages have a single generic formal parameter, which is the package
Ada.Numerics.Generic_Complex_Types; the actual parameter can be any instantiation of the package obtained by supplying a floating point type for the formal parameterReal.
Case study: complex vectors
Here is the outline of a package for complex vectors that is generic in the complex type package
‡8–9and the complex elementary function package‡10–11. For simplicity, the package contains only one subprogram.
- - File: COMPLEX
1 - -
2 - - Complex vectors using generic package parameters.
3 - -
4 withAda.Numerics.Generic_Complex_Types;
10.8 Advanced concepts* 176
6 generic
7 use Ada.Numerics;
8 with packageComplex_Types is
9 newGeneric_Complex_Types (<>);
10 with packageComplex_Functions is
11 newGeneric_Complex_Elementary_Functions(Complex_Types);
12 packageGeneric_Complex_Vectors is
13 type Vector(<>)is private;
14 functionDistance(Left, Right: Vector)returnComplex_Types.Real’Base;
15 private
16 type Vectoris array(Integerrange <>)of Complex_Types.Complex;
17 endGeneric_Complex_Vectors;
18
19 package bodyGeneric_Complex_Vectors is
20 use Complex_Types;
21 functionDistance(Left, Right: Vector)returnRealis
22 Sum: Complex := Compose_From_Cartesian(0.0);
23 begin
24 forNin Left’Range loop
25 Sum := Sum + Left(N) * Right(N);
26 end loop;
27 return abs(Complex_Functions.Sqrt(Sum));
28 endDistance;
29 endGeneric_Complex_Vectors;
The actual parameters of the instantiation‡36–37 Complex_Vectorsare the predefined packages forFloat, which are considered to be equivalent to instantiations of the generic packages.
30 withAda.Numerics.Complex_Types;
31 withAda.Numerics.Complex_Elementary_Functions;
32 withGeneric_Complex_Vectors;
33 packageComplex_Vectors is new
34 Generic_Complex_Vectors(
35 Ada.Numerics.Complex_Types,
36 Ada.Numerics.Complex_Elementary_Functions);
Alternatively, if we have defined our own floating point type, we can instantiate in sequence the generic packages for complex types, complex elementary functions and complex vectors.
37 packageSignalsis
38 type Realis digits12;
39 endSignals; 40 41 withSignals; 42 withAda.Numerics.Generic_Complex_Types; 43 packageSignals_Complex is 44 newAda.Numerics.Generic_Complex_Types(Signals.Real);
10.8 Advanced concepts* 177
45
46 withSignals;
47 withSignals_Complex;
48 withAda.Numerics.Generic_Complex_Elementary_Functions;
49 packageSignals_Complex_EF is new
50 Ada.Numerics.Generic_Complex_Elementary_Functions(Signals_Complex);
51
52 withSignals_Complex;
53 withSignals_Complex_EF;
54 withGeneric_Complex_Vectors;
55 packageSignals_Complex_Vectors is new
56 Generic_Complex_Vectors(Signals_Complex, Signals_Complex_EF);
In Section 7.10 we noted that a generic package can have a generic child. The following pack- age extends the complex vector abstraction by creating an abstraction of a pair of vectors that is implemented‡63–66using the full view of the typeVectorthat is visible to a child package. Sig- nals_Complex_Vectors.Pairis created by instantiating‡71–72the generic childGeneric_Pairof theinstanceSignals_Complex_Vectors.
57 generic
58 packageGeneric_Complex_Vectors.Generic_Pairis
59 type Pair is private;
60 private
61 subtypeMaxis Integerrange 0..100;
62 type Pair(Size: Max := 10)is
63 record
64 First, Second: Vector(1..Size);
65 end record; 66 endGeneric_Complex_Vectors.Generic_Pair; 67 68 withSignals_Complex_Vectors; 69 with Generic_Complex_Vectors.Generic_Pair; 70 packageSignals_Complex_Vectors.Pair is 71 newSignals_Complex_Vectors.Generic_Pair;
Preference for root types**
What is the type ofNin the following loop statement? for Nin 1..100loop
Since the literals are of typeuniversal_integer, the type should be ambiguous, because there is no context that can be used to convert the range to a specific type. The following rules are used to resolve the ambiguity:
§8.6
29 There is apreferencefor the primitive operators (and ranges) of the root numeric typesroot_integerandroot_real.
10.8 Advanced concepts* 178
§3.6
18 If the type of the range resolves to root_integer, then the dis- crete_subtype_definition defines a subtype of the predefined type Integer with bounds given by a conversion toIntegerof the bounds of therange;
1..100is resolved by preference toroot_integerand defines a subtype of typeInteger.
For another example, consider the following program, which prints"OK"because of the prefer- ence for root numeric types, even though"<"could refer to the ‘strange’ operator that we have defined for predefinedInteger!
- - File: PREF
1 withAda.Text_IO; use Ada.Text_IO;
2 procedure Prefis
3 function"<"(Left, Right: Integer) returnBoolean is
4 begin
5 returnLeft >= Right;
6 end"<";
7 begin
8 if5 < 4then Put("Strange");else Put("OK");end if;
9 endPref;
Model numbers**
§3.5.7
8 The set of values for a floating point type is the (infinite) set of rational numbers. Themachine numbersof a floating point type are the values of the type that can be represented exactly in every unconstrained variable of the type. . . .
The accuracy of floating point computation is defined in Annex §G, using an idealization of ma- chine numbers calledmodel numbers. Some values of floating point type, such as 0.510=0.12, are equal to model numbers; others, such as 0.210 = 0.00110011. . .2 that do not equal model num- bers are represented by themodel intervalbetween the model numbers closest to the value.3 An arithmetical operation between two model intervals yields another model interval. These concepts are used to define the accuracy of computation with real types.
An implementation may find some accuracy requirements difficult to achieve efficiently. In addi- tion to the requiredstrict mode of computation that fully conforms with the standard, an imple- mentation may offer arelaxed modeof computation §G.2(1–3).
If you are interested in numeric computation, you will want to read Annex §Gof theRationale, which explains both complex arithmetic and model numbers in detail.