There are many situations where it is desirable for programmers to define their own types. For example:
i.e. to produce more reliable programs. Programmer-defined types are presented using a type declaration statement. This binds a "new" type definition to a type name (whereas a data declaration statement binds an existing type definition to a data item name). Type declaration statements have the general form:
type <TYPE_NAME> is <TYPE DEFINITION> ;
Some example type declarations incorporating specific ranges and/or precisions:
type SCORE is range 0 .. 100; type TEMPERATURE is digits 3; type PERCENTAGE is digits 4 range 0.0 .. 100.0;
Note that in each case the compiler will deduce that the types SCORE and TEMPERATURE are integer types. Similarly the compiler will deduce that the type PERCENTAGE is a floating point type, but only (in the case of the ICC compiler) if the number of digits is also specified. For example X: FLOAT is range 0.0 .. 100.0; will not compile. Once the above types have been declared they can be utilised in the usual manner:
A_VALUE: SCORE; SUMMER: TEMPERATURE := 20; X_VALU, Y_VALU: PERCENTAGE := 100.0;
A type declaration statement can also be used to rename an existing type, for example to use a more descriptive (application dependent) type name for a particular type. For example:
type REAL is float;
Here an alternative name for the pre-defined type FLOAT has been declared.
To produce a program that converts air temperature measured in whole numbers of degrees on the Centigrade scale to the equivalent on the Fahrenheit scale. Assume a minimum centigrade temperature of -50 and maximum of 100. Use the following conversion identity:
F = (9/5 x C) + 32
Output should be accurate to one decimal place.
Commence with a top down analysis of the problem as illustrated by the hierarchy presented below:
A single procedure will be sufficient to implement these operations:
NAME | DESCRIPTION | TYPE | RANGE |
---|---|---|---|
CENT_TEMP | Input variable | CENTIGRADE | -50..100 |
A Nassi-Shneiderman design is presented to the right.
-- CENTIGRADE TO FAHRENHEIT CONVERSION -- 4 August 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure CENT_2_FAHR is type CENTIGRADE is range -50..100; package INTEGER_INOUT is new INTEGER_IO(CENTIGRADE); use INTEGER_INOUT; package FLOAT_INOUT is new FLOAT_IO(FLOAT); use FLOAT_INOUT; CENT_TEMP: CENTIGRADE; begin -- Input centigrade value PUT_LINE("Input temperature in degrees Centigrade: "); GET(CENT_TEMP); -- Conversion and output PUT("The equivalent in degrees Fahrenheit is: "); PUT(FLOAT(CENT_TEMP) * (9.0/5.0) + 32.0, FORE=>3, AFT=>1, EXP=>0); NEW_LINE; end CENT_2_FAHR;
Notes
TEST CASE | EXPECTED RESULT |
---|---|
CENT_TEMP | FAHR_TEMP |
-51 | DATA_ERROR |
-50 | -58.0 |
-49 | -56.2 |
99 | 210.2 |
100 | 212.0 |
101 | DATA_ERROR |
BVA and limit testing: Use Boundary Value Analysis testing to analyse limits of input variables. Suitable boundary values for CENT_TEMP are -51, -49, 99 and 101 (just above and below the range limits). We should also test the effect of inputs at the limits, e.g. -50 and 100. An appropriate set of test cases is given in the table (right).
Arithmetic testing: In addition we should also carry out some arithmetic testing to ensure the calculation part of the program operates appropriately. This normally involves tests using positive, zero and negative sample input values. Test cases involving positive and negative input values have already been designed with respect to BVA testing (see above) thus we only need to consider an input value of 0. An appropriate test case is defined in the table (right).
TEST CASE | EXPECTED RESULT |
---|---|
CENT_TEMP | FAHR_TEMP |
0 | 32 |
Data validation testing: Finally the code should be tested using a number of spurious input values not previously incorporated into test cases.
Example Problem Centigrade to Fahrenheit Conversion Report.
Given a particular problem it is sometimes useful to introduce a type which can take values that are some subset of an existing type. Such types are referred to as subtypes. Subtypes are declared in a very similar manner to that in which programmer defined type declarations are made except that the keyword subtype is used. Examples of subtype declarations can be found in the package standard that is always automatically linked in to Ada programs and therefore does not require with and use statements). This package (amongst other things) contains two subtypes of the type INTEGER which are declared as follows:
subtype NATURAL is INTEGER range 0..INTEGER'LAST; subtype POSITIVE is INTEGER range 1..INTEGER'LAST;
(note the use of the integer attribute last). Use of subtypes offers similar advantages to those associated with the use of programmer defined types:
Both offer similar advantages when closely related objects are in use and many computations are to be made using them. However, generally speaking, where a data item is required to display many of the features of the standard INTEGER or FLOAT types a subtype declaration should be used. Type declarations are usually used to describe what are termed compound types (e.g. arrays), but more on this later.
Given the start velocity of a ball which is thrown vertically upwards from ground level, design and implement an Ada program that determines:
Assume that the start velocity is an integer between 1 and 100m/s (inclusive) and that deceleration due to gravity is equivalent -10 m/s^2. Use the equation:
h = u^2 / -2g
where u = start velocity and g = deceleration due to gravity, to calculate the maximum height (h). Use the equation:
t = (4 x h) / u
to calculate total time (t) taken to return to the ground. Output should be accurate to two decimal places.
The operations identified in the above top level analysis can be combined into the following three procedures/functions.
NAME | DESCRIPTION | TYPE | VALUE/ RANGE |
---|---|---|---|
START_VELOCITY | Input global variable | VELOCITY | 1..100 |
DECELERATION | Global constant | FLOAT | -10.0 |
MAX_HEIGHT | Global variable | FLOAT | Default |
NAME | DESCRIPTION | TYPE | VALUE/ RANGE |
---|---|---|---|
START_VELOCITY | Formal parameter | VELOCITY | 1..100 |
MAX_HEIGHT | Local variable | FLOAT | Default |
NAME | DESCRIPTION | TYPE | VALUE/ RANGE |
---|---|---|---|
START_VELOCITY | Formal parameter | VELOCITY | 1..100 |
MAX_HEIGHT | Formal parameter | FLOAT | Default |
The design detail for these procedures/functions is expressed by the set of Nassi-Shneiderman charts given below.
Commence the implementation with the top top level procedure and only implement the second level using stubs.
-- VERTICAL MOTION -- 9 September 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure VERT_MOTION is subtype VELOCITY is INTEGER range 1..100; package INTEGER_INOUT is new INTEGER_IO(INTEGER); use INTEGER_INOUT; package FLOAT_INOUT is new FLOAT_IO(FLOAT); use FLOAT_INOUT; START_VELOCITY: VELOCITY; DECELERATION: constant := -10.0; MAX_HEIGHT: FLOAT; ------------------------------------------------------------------------ -- CALCULATE MAXIMUM HEIGHT function MAXIMUM_HEIGHT(START_VELOCITY: VELOCITY) return FLOAT is begin PUT("In MAXIMUM_HEIGHT function, START_VELOCITY = "); PUT(START_VELOCITY); NEW_LINE; RETURN(1.0); end MAXIMUM_HEIGHT; ------------------------------------------------------------------------ -- CALCULATE TOTAL TIME procedure TOTAL_TIME(START_VELOCITY: VELOCITY; MAX_HEIGHT: FLOAT) is begin PUT("In TOTAL_TIME function, START_VELOCITY = "); PUT(START_VELOCITY); PUT(", MAX_HEIGHT = "); PUT(MAX_HEIGHT); NEW_LINE; end TOTAL_TIME; ------------------------------------------------------------------------ -- TOP LEVEL begin -- Input start velocity PUT_LINE("Input start velocity (integer value between 1 and 100): "); GET(START_VELOCITY); -- Calculate maximum height; MAX_HEIGHT := MAXIMUM_HEIGHT(START_VELOCITY); -- Calculate total time; TOTAL_TIME(START_VELOCITY, MAX_HEIGHT); end VERT_MOTION;
Note that when using subtypes it is sufficient to create an input/output package for the super type (INTEGER or FLOAT as appropriate. We do not need to create individual packages for each subtype.
TEST CASE | EXPECTED RESULT |
---|---|
START_VELOCITY | |
0 | CONSTRAINT_ERROR |
1 | O.K. |
2 | O.K. |
99 | O.K. |
100 | O.K. |
101 | CONSTRAINT_ERROR |
On completion of this first level implementation we should test the operation of the program using (in this case) a set of BVA and limit test cases of the form given to the right. On satisfactory completion this testing stage we can commence the second level implementation.
-- VERTICAL MOTION -- 9 September 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure VERT_MOTION is subtype VELOCITY is INTEGER range 1..100; package INTEGER_INOUT is new INTEGER_IO(INTEGER); use INTEGER_INOUT; package FLOAT_INOUT is new FLOAT_IO(FLOAT); use FLOAT_INOUT; START_VELOCITY: VELOCITY; DECELERATION: constant := -10.0; MAX_HEIGHT: FLOAT; ------------------------------------------------------------------------ -- CALCULATE MAXIMUM HEIGHT function MAXIMUM_HEIGHT(START_VELOCITY: VELOCITY) return FLOAT is MAX_HEIGHT: FLOAT; begin MAX_HEIGHT := (FLOAT(START_VELOCITY)**2)/(-2.0*DECELERATION); PUT("Maximum height reached = "); PUT(MAX_HEIGHT, FORE=>4, AFT=>2, EXP=>0); PUT(" m"); NEW_LINE; RETURN(MAX_HEIGHT); end MAXIMUM_HEIGHT; ------------------------------------------------------------------------ -- CALCULATE TOTAL TIME procedure TOTAL_TIME(START_VELOCITY: VELOCITY; MAX_HEIGHT: FLOAT) is begin PUT("Total time to return to ground = "); PUT(4.0*MAX_HEIGHT/FLOAT(START_VELOCITY), FORE=>4, AFT=>2, EXP=>0); PUT(" s"); NEW_LINE; end TOTAL_TIME; ------------------------------------------------------------------------ -- TOP LEVEL begin -- Input start velocity PUT_LINE("Input start velocity (integer value between 1 and 100): "); GET(START_VELOCITY); -- Calculate maximum height; MAX_HEIGHT := MAXIMUM_HEIGHT(START_VELOCITY); -- Calculate total time; TOTAL_TIME(START_VELOCITY, MAX_HEIGHT); end VERT_MOTION;
TEST CASE | EXPECTED RESULT | |
---|---|---|
START_VELOCITY | MAX_HEIGHT | Total time |
0 | CONSTRAINT_ERROR | |
1 | 0.05 | 0.20 |
2 | 0.20 | 0.40 |
99 | 490.05 | 19.80 |
100 | 500.00 | 20.00 |
101 | CONSTRAINT_ERROR |
Use BVA (Boundary Value Analysis) and limit testing to analyse and test limits of input variables. Suitable boundary and limit values for START_VELOCITY are 0, 1, 2, 99, 100 and 101. An appropriate set of test cases is given in the table (right).
TEST CASE | EXPECTED RESULT | |
---|---|---|
START_VELOCITY | MAX_HEIGHT | Total time |
50 | 125.00 | 10.00 |
Use arithmetic testing techniques to test the arithmetic expressions. Test using positive values only in this case (negative and zero values precluded by input type definition in this case). Positive value already included in BVA and limit test cases, however, we should include a test somewhere in the middle of the range
Finally include some data validation test cases.
Example Problem Vertical Motion Report.
Created and maintained by Frans Coenen. Last updated 11 October 1999