RANGE AND PRECISION


1. OVERVIEW

The most high level approach to defining range/precision is through explicit specification. This is supported by Ada. Examples of data item declarations where specific ranges and/or precision are defined:

A_VALUE: INTEGER range 0 .. 100;

SUMMER: INTEGER is digits 3;

X_VALUE, Y_VALUE; FLOAT is digits 4  range 0.0 .. 100.0;

Note that, where appropriate, precision (number of digits) must be specified before range. The specification of ranges and/or precisions for data items (at least with respect to Ada) facilitates automatic checking of values. This is especially useful where input variables are required to be within a specific range or of a certain precision.

Note: precision is not the same as requiring output to be to a certain number of decimal places.


2. EXAMPLE PROBLEM PYTHAGORAS


2.1. Requirements

TRIANGLE

Given the length of the "opposite" (O) and "adjacent" (A) sides of a right angled triangle (see right) determine the "hypotenuse" (H) using Pythagoras theorem:

H^2 = O^2 + A^2

Assume sides are given as floating point numbers between 0.0 and 100.0 and that an accuracy of 4 decimal places is required


2.2. Design

Using a top down analysis of the problem we can identify the operations shown below:

NASSI_SHNEIDERMAN CHART

These operations are trivial enough to be encompassed by a single procedure:

  1. PYTHAGORAS (top level procedure) - read in short sides and calculate and output long side.
    NAMEDESCRIPTIONTYPERANGE
    OPPOSITEInput variableFLOAT0.0..100.0
    ADJACENTInput variableFLOAT0.0..100.0
    HYPOTENUSEGlobal variableFLOAT0.0..100.0
NASSI_SHNEIDERMAN CHART

A Nassi-Shneiderman design is presented to the right.


2.3. Implementation

The implementation of the design is as follows:


-- PYTHAGORAS
-- 6 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO, GENERIC_ELEMENTARY_FUNCTIONS;
use TEXT_IO;

procedure PYTHAGORAS is
        OPPOSITE, ADJACENT: FLOAT range 0.0..100.0;
        HYPOTENUSE: FLOAT;
        package FLOAT_INOUT is new FLOAT_IO(FLOAT);
        use FLOAT_INOUT;
        package MATH_FUNC is new GENERIC_ELEMENTARY_FUNCTIONS(FLOAT);
        use MATH_FUNC;
begin
-- Input opposite and adjacent side
        PUT_LINE("Input opposite and adjacent sides: ");
        GET(OPPOSITE);
        GET(ADJACENT);
-- Calculate hypotenuse
        HYPOTENUSE := OPPOSITE**2 + ADJACENT**2;
        HYPOTENUSE := SQRT(HYPOTENUSE);
-- Output hypotenuse
        PUT("Hypotenuse is: ");
        PUT(HYPOTENUSE, FORE=>3, AFT=>4, EXP=>0);
        NEW_LINE;
end PYTHAGORAS;

Notes:

  1. To use mathematical functions, such as SQRT, in a program we must ensure that the program has access to the appropriate mathematical package by specifying the name of the package at the beginning of the program. The SQRT function is contained in the standard package GENERIC_ELEMENTARY_FUNCTIONS.
  2. However, the package GENERIC_ELEMENTARY_FUNCTIONS is not a complete package, but rather a template for a package known as a generic package. Therefore, you cannot simply refer to it with a use statement at the beginning of the program. Instead, within the program, we need to create a new package using an appropriate template in the same way that was used to create I/O packages for integer and floating point types. Thus:
      package PACKAGE_NAME is new TEMPLATE_NAME(T);
      use PACKAGE_NAME;
      
    where T is a type name. The required template is also called GENERIC_ELEMENTARY_FUNCTIONS, and in the above case we have named the new package MATH_FUNC.
  3. We have used the FLOAT_IO template contained in TEXT_IO to create an I/O package for the floating point types.

2.4. Testing

TEST CASEEXPECTED RESULT
OPPOSITEADJACENTHYPOTENUSE
-0.1 * CONSTRAINT_ERROR
0.1 -0.1CONSTRAINT_ERROR
0.1 0.10.1414
99.9 99.9141.2799
99.9100.1CONSTRAINT_ERROR
101.1 * CONSTRAINT_ERROR

BVA Testing: When using "ranged" types it has been demonstrated that errors often occur at the boundaries of the input domain. It is for this reason that Boundary Value Analysis (BVA) has been developed as a testing technique. Boundary value analyses leads to a selection of test cases that exercise bounding values for data items. At its simplest this involves the derivation of test cases with values just above and just below the bounding values. Thus suitable boundary values for both OPPOSITE and ADJACENT are -0.1, 0.1, 99.9 and 100.1. An appropriate set of test cases is given in the table (above-right), where the * symbol indicates that no further input is required as we expect the code to fail after the previous input. Note that values for ADJACENT can only be tested given valid values for OPPOSITE.

TEST CASEEXPECTED RESULT
OPPOSITEADJACENTHYPOTENUSE
0.0 0.00.0
0.0100.0100.0
100.0 0.0100.0
100.0100.0141.4214

Limit testing: Ranged input data items should also be tested at their limits, i.e at their maximum and minimum permitted values. Two suitable test cases are given in the table to the right.

Data validation testing: We should also test the input with some spurious inputs, e.g. characters or too many inputs.

TEST CASEEXPECTED RESULT
OPPOSITEADJACENTHYPOTENUSE
0.0 0.0 0.0
0.0 10.010.0
10.0 0.010.0
10.0 10.014.1421

Arithmetic testing Finally use straightforward arithmetic testing to test calculation. Normally this would require positive, zero and negative sample values for each input. However, in this case we need only to consider positive and zero values. A suitable set of test cases is given to the right.


Example Problem Pythagoras Report.


3. EXAMPLE PROBLEM 2-D GEOGRAPHIC DISTANCE


3.1 Requirements

Design and implement an Ada program that determines the geographical distance between two points located on a geographic plane. The points are referenced using the standard {X,Y} Cartesian coordinate system founded on a 0 origin (see below). The geographic space of interest measures 100x100. X and Y Coordinates can therefore range from 0.0 to 100.0 inclusive. Distances should be determined to within 4 decimal places.

2-D SPACE

3.2 Design

The distance between two two-dimensional points is given by:

DISTANCE = SQRT(X^22 + Y^2)

where X and Y respectively represent the difference between the pairs of x and y coordinates for the two points. To address this problem we can identify a number of operations as indicated by the top-down analysis presented below:

TOP DOWN DESIGN

These operations are simple enough to be combined into a single procedure:

  1. GEO_DIST_2D (top level procedure) - input data, and calculate and output distance.
    NAMEDESCRIPTIONTYPERANGE
    X1Input variableFLOAT0.0..100.0
    Y1Input variableFLOAT0.0..100.0
    X2Input variableFLOAT0.0..100.0
    Y2Input variableFLOAT0.0..100.0
    X_DIFFGlobal variableFLOATDefault
    Y_DIFFGlobal variableFLOATDefault
    DISTANCEGlobal variableFLOATDefault

The design of this procedure is indicated by the Nassi-Shneiderman chart presented below.

NASSI_SHNEIDERMAN CHART

3.3. Implementation

-- 2D GEOGRAPHIC DISTANCE
-- 4 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO, GENERIC_ELEMENTARY_FUNCTIONS;
use TEXT_IO;

procedure GEO_DIST_2D is
        X1, Y1, X2, Y2: FLOAT range 0.0..100.0;
        X_DIFF, Y_DIFF, DISTANCE: FLOAT;
        package FLOAT_INOUT is new FLOAT_IO(FLOAT);
        use FLOAT_INOUT;
        package MATH_FUNC is new GENERIC_ELEMENTARY_FUNCTIONS(FLOAT);
        use MATH_FUNC;
begin
-- Input coordinates for point 1
        PUT_LINE("Input X and Y coordinates for point 1: ");
        GET(X1);
        GET(Y1);
-- Input coordinates for point 2
        PUT_LINE("Input X and Y coordinates for point 2: ");
        GET(X2);
        GET(Y2);
-- Calculate differences and distance
        X_DIFF := abs(X1-X2);
        Y_DIFF := abs(Y1-Y2);
        DISTANCE := SQRT(X_DIFF**2 + Y_DIFF**2);
-- Output distance
        PUT("Distance is: ");
        PUT(DISTANCE, FORE=>3, AFT=>4, EXP=>0);
        NEW_LINE;
end GEO_DIST_2D;

Note that the abs operator is a standard numeric operator which has one operand that can be of any arbitrary numeric type. The operator calculates the absolute value (or magnitude) of the operand, i.e. the operand itself if it is positive, and the negated operand if it is negative.


3.4. Testing

TEST CASEEXPECTED RESULT
X1Y1X2Y2DISTANCE
-0.1 * * * CONSTRAINT_ERROR
100.1 * * * CONSTRAINT_ERROR
0.1 -0.1 * * CONSTRAINT_ERROR
99.9100.1 * * CONSTRAINT_ERROR
0.1 0.1 -0.1 * CONSTRAINT_ERROR
99.9 99.9100.1 * CONSTRAINT_ERROR
0.1 0.1 0.1 -0.1CONSTRAINT_ERROR
99.9 99.9 99.9100.1CONSTRAINT_ERROR
0.1 99.9 99.9 0.1141.1385
99.9 0.1 0.1 99.9141.1385

BVA testing: Use BVA to test limits of input values. Appropriate values for X1, Y1, X2 and Y2 are -0.1, 0.1, 99.9 and 100.1 (just above and below the range limits). A set of test cases of this form is presented in the table to the right. The * symbol indicates where no further input is required as the code is expected to fail after the previous input.

Arithmetic testing: We should also carry out a set of numeric tests to check the workings of the arithmetic expressions. This could be done by generating a set of cases combining every possible combination of zero and positive sample input value (negative values are precluded in this case), i.e. 2 x 2 x 2 x 2 = 16 test cases. This would be rather tedious (and with more inputs impractical). We can reduce the amount of test cases required by investigating more closely the arithmetic operations we wish to check. There are three of these:

1.Difference in X calculation
2.Difference in Y calculation
3.Pythagoras calculation

SAMPLE VALUESEXPECTED RESULT
X1 Y1 X2 Y2 X_DIFF Y_DIFF
0 0 0 0 00
+ve+ve 0 0+ve+ve
0 0+ve+ve+ve+ve
+ve+ve+ve+ve+ve or 0+ve or 0

Commencing with the two difference calculations, we note that each is carried out independently from the other and thus can be tested simultaneously. Each should be tested with combinations of positive and zero sample values. An outline set of required test cases is given in the table to the right.

SAMPLE VALUES
X_DIFF Y_DIFF
0 0
+ve 0
0+ve
+ve+ve

Turning to the Pythagoras calculation this should be tested with sample values for X_DIFF and Y_DIFF comprising all possible combinations of zero and positive value (we cannot have a negative difference) as shown in the table to the right. Test cases required to check the difference calculation already identify the situation where both difference values are zero and both difference values are positive. We therefore simply need to derive two test cases where one or the other difference value is zero .

An appropriate set of numeric test cases with respect to the foregoing is given below. Note that we have reduced the number of arithmetic tests from 16 to 6. The first four of the following address the difference calculations and also the Pythagoras calculation where both differences are 0 and both differences are positive. The final two test cases are designed to exercise the Pythagoras calculation where one of the differences is zero and the other is positive (and vice-versa).

TEST CASEEXPECTED RESULT
X1Y1X2Y2DISTANCE
0.0 0.0 0.0 0.0 0.0000
0.0 0.0 10.0 10.0 14.1421
10.0 10.0 0.0 0.0 14.1421
10.0 10.0 10.0 10.0 0.0000
20.0 10.0 20.0 30.0 20.0000
30.0 20.0 10.0 20.0 20.0000

Limit testing: We should also test the operations of the systems at the limits for the input data. Notionally there are four tests for each difference calculation covering every combination of 0.0 and 100.0 input. However, the above arithmetic test cases have considered the case where inputs are all 0.0. Therefore we only need to test combinations where one or both of the input is 100.0. An appropriate set of test cases is given in the table below.

TEST CASEEXPECTED RESULT
X1Y1X2Y2DISTANCE
100.0 0.0 0.0100.0141.4214
0.0100.0100.0 0.0141.4214
100.0100.0100.0100.0 0.0000

Data validation: Finally we should carry out some tests using deliberately spurious data.


Example Problem 2D Geographic Distance Report.




Created and maintained by Frans Coenen. Last updated 11 October 1999