[Ada Information Clearinghouse]

Ada '83 Quality and Style:

Guidelines for Professional Programmers

Copyright 1989, 1991,1992 Software Productivity Consortium, Inc., Herndon, Virginia.

CHAPTER 7: Portability

7.2 Numeric Types and Expressions

A great deal of care was taken with the design of the Ada features related to numeric computations to ensure that the language could be used in embedded systems and mathematical applications where precision was important. As far as possible, these features were made portable. However, there is an inevitable tradeoff between maximally exploiting the available precision of numeric computation on a particular machine and maximizing the portability of Ada numeric constructs. This means that these Ada features, particularly numeric types and expressions, must be used with great care if full portability of the resulting program is to be guaranteed.
In this section...
7.2.1 Predefined Numeric Types
7.2.2 Ada Model
7.2.3 Analysis
7.2.4 Accuracy Constraints
7.2.5 Comments
7.2.6 Precision of Constants
7.2.7 Subexpression Evaluation
7.2.8 Relational Tests
Summary of Guidelines from this section


7.2.1 Predefined Numeric Types

guideline

example

The second and third examples below are not representable as subranges of Integer on a machine with a 16-bit word. The first example below allows a compiler to choose a multiword representation if necessary.

Use

    type    Second_Of_Day is             range 0 .. 86_400;
rather than
    type    Second_Of_Day is new Integer range 1 .. 86_400;
or
    subtype Second_Of_Day is     Integer range 1 .. 86_400;

rationale

An implementor is free to define the range of the predefined numeric types. Porting code from an implementation with greater accuracy to one of lesser is a time consuming and error-prone process. Many of the errors are not reported until run-time.

This applies to more than just numerical computation. An easy-to-overlook instance of this problem occurs if you neglect to use explicitly declared types for integer discrete ranges (array sizes, loop ranges, etc.) (see Guidelines 5.5.1 and 5.5.2). If you do not provide an explicit type when specifying index constraints and other discrete ranges, a predefined integer type is assumed.

exceptions

Any indexing into the predefined String type requires that the index at least be a subtype of the predefined Integer type. The predefined packages also use the various predefined types.

note

There is an alternative which this guideline permits. As Guideline 7.1.5 suggests, implementation dependencies can be encapsulated in packages intended for that purpose. This could include the definition of a 32-bit integer type. It would then be possible to derive additional types from that 32-bit type.

Language Ref Manual references: 3.5.4 Integer Types, 3.5.7 Floating Point Types, 3.5.9 Fixed Point Types, 8.6 The Package Standard, C Predefined Language Environment, F Implementation-Dependent Characteristics


7.2.2 Ada Model

guideline

rationale

Declarations of Ada floating point types give users control over both the representation and arithmetic used in floating point operations. Portable properties of Ada programs are derived from the models for floating point numbers of the subtype and the corresponding safe numbers. The relative spacing and range of values in a type are determined by the declaration. Attributes can be used to specify the transportable properties of an Ada floating point type.

Language Ref Manual references: 3.5.7 Floating Point Types, 4.5.7 Accuracy of Operations with Real Operands


7.2.3 Analysis

guideline

rationale

Floating point calculations are done with the equivalent of the implementation's predefined floating point types. The effect of extra "guard" digits in internal computations can sometimes lower the number of digits that must be specified in an Ada declaration. This may not be consistent over implementations where the program is intended to be run. It may also lead to the false conclusion that the declared types are sufficient for the accuracy required.

The numeric type declarations should be chosen to satisfy the lowest precision (smallest number of digits) that will provide the required accuracy. Careful analysis will be necessary to show that the declarations are adequate.

Language Ref Manual references: 3.5.7 Floating Point Types, 4.5.7 Accuracy of Operations with Real Operands, 13.7.3 Representation Attributes of Real Types


7.2.4 Accuracy Constraints

guideline

rationale

The Ada floating point model is intended to facilitate program portability, which is often at the expense of efficiency in using the underlying machine arithmetic. Just because two different machines use the same number of digits in the mantissa of a floating point number does not imply they will have the same arithmetic properties. Some Ada implementations may give slightly better accuracy than required by Ada because they make efficient use of the machine. Do not write programs that depend on this.

Language Ref Manual references: 4.5.7 Accuracy of Operations with Real Operands, F Implementation-Dependent Characteristics


7.2.5 Comments

guideline

rationale

Decisions and background about why certain precisions are required in a program are important to program revision or porting. The underlying numerical analysis leading to the program should be commented.

Language Ref Manual references: 2.7 Comments, 3.5.4 Integer Types, 3.5.6 Real Types, 4.5.7 Accuracy of Operations with Real Operands


7.2.6 Precision of Constants

guideline

rationale

For a given radix (number base), there is a loss of accuracy for some rational and all irrational numbers when represented by a finite sequence of digits. Ada has named numbers and expressions of type universal_real that provide maximal accuracy of representation in the source program. These numbers and expressions are converted to finite representations at compile time. By using universal real expressions and numbers, the programmer can automatically delay the conversion to machine types until the point where it can be done with the minimum loss of accuracy.

note

See also Guideline 3.2.5.

Language Ref Manual references: 2.4 Numeric Literals, 3.2 Objects and Named Numbers, 4.1 Universal Expressions, 4.9 Static Expressions and Static Subtypes


7.2.7 Subexpression Evaluation

guideline

rationale

The Ada language does not require that an implementation perform range checks on subexpressions within an expression. Even if the implementation on your program's current target does not perform these checks, your program may be ported to an implementation that does.

Language Ref Manual references: 3.3 Types and Subtypes, 3.3.2 Subtype Declarations, 3.4 Derived Types, 4.4 Expressions, 4.5 Operators and Expression Evaluation, 4.5.7 Accuracy of Operations with Real Operands


7.2.8 Relational Tests

guideline

example

The following examples test for (1) absolute "equality" in storage, (2)
absolute "equality" in computation, (3) relative "equality" in storage, and (4) relative "equality" in computation.
abs (X - Y) <= Float_Type'Small                -- (1)

abs (X - Y) <= Float_Type'Base'Small           -- (2)

abs (X - Y) <= abs X * Float_Type'Epsilon      -- (3)

abs (X - Y) <= abs X * Float_Type'Base'Epsilon -- (4)

And specifically for "equality" to zero:
abs X <= Float_Type'Small                      -- (1)

abs X <= Float_Type'Base'Small                 -- (2)

abs X <= abs X * Float_Type'Epsilon            -- (3)

abs X <= abs X * Float_Type'Base'Epsilon       -- (4)

rationale

Strict relational comparisons ( <, >, =, /= ) are a general problem in real valued computations. Because of the way Ada comparisons are defined in terms of model intervals, it is possible for the values of the Ada comparisons A < B and A = B to depend on the implementation, while A <= B evaluates uniformly across implementations. Note that for real values in Ada, "A <= B" is not the same as "not (A > B)". Further explanation can be found in Cohen (1986) pp.227-233.

Type attributes are the primary means of symbolically accessing the implementation of the Ada numeric model. When the characteristics of the model numbers are accessed symbolically, the source code is portable. The appropriate model numbers of any implementation will then be used by the generated code.

Although zero is technically not a special case, it is often overlooked because it looks like the simplest and, therefore, safest case. But in reality, each time comparisons involve small values, evaluate the situation to determine which technique is appropriate.

note

Regardless of language, real valued computations have inaccuracy. That the corresponding mathematical operations have algebraic properties usually introduces some confusion. This guideline explains how Ada deals with the problem that most languages face.

Language Ref Manual references: 4.5.2 Relational Operators and Membership Tests


Back to document index