To produce a program that calculates and outputs the circumference and area of a circle given its radius. Assume "PI" is equivalent to 3.14159 and that the radius is input by the user as a floating point number. Area of a circle = PI x diameter = 2 x PI x radius, and Circumference = PI x radius^2.
Adopting a top down analysis approach to the above problem:
we can identify several operations. These operations are simple enough to be wrapped up into a single procedure -
Note that the procedure will need to include definitions for two data items: (1) the constant PI and (2) a variable in which to hold the input. It is a good idea to define the nature of data items required bu a procedure in a tabular format (even if there is only 1) as this information is required for testing purposes:
NAME | DESCRIPTION | TYPE | VALUE/RANGE |
---|---|---|---|
PI | Global constant | FLOAT | 3.14 |
RADIUS | Global input variable | FLOAT | Default |
The detailed design for this procedure is given by the N-S chart to the right.
-- CIRCLE CALCULATION -- 7 August 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with CS_IO; use CS_IO; procedure CIRCLE_CALC is PI: constant := 3.14; RADIUS: FLOAT; begin PUT_LINE("Input radius: "); GET(RADIUS); -- Calculate circumference using 2xPIxRadius PUT("The circumference is: "); put(2.0*PI*RADIUS, FORE => 3, AFT => 4, EXP => 0); NEW_LINE; -- Calculate area using PIxRadius^2 PUT("The area is: "); put(PI*RADIUS**2, FORE => 3, AFT => 4, EXP => 0); NEW_LINE; end CIRCLE_CALC;
Some points to note about the above code:
PUT(REAL_VALUE, FORE=>N, AFT=>M, EXP=>0);indicate the format for the output of real values, N and M give the number of figures before or after the decimal point. If we simply write:
PUT(REAL_VALUE);The output will be in scientific notation. For example:
Input radius: 10.0 The circumference is: 6.28000000000000E+01 The area is: 3.14000000000000E+02which should be interpreted as 6.28x10^1 (62.8) and 3.14x10^2 (314) respectively.
TEST CASE | EXPECTED RESULT | |
---|---|---|
RADIUS | CIRCUMFERENCE | AREA |
10.0 | 62.8000 | 314.0000 |
0.0 | 0.0000 | 0.0000 |
-10.0 | -62.8000 | 31.4000 |
Arithmetic testing: Test using negative, positive and zero input values for RADIUS as shown in the table (right). Note that when we input a negative number we produce a negative circumference - this is probably not the desired result and thus we should return to the requirements phase and determine what action we should take in the event of a negative radius - (a) error, (b) convert to a positive number, (c) ... ?
Data validation testing: We should also include some tests using input data which id deliberately of the wrong type or to many inputs, no inputs etc.
Example Problem Circle Calculation Report.
To produce a program that calculates the surface area and volume of a cylinder given its diameter and height. Assume "PI" is equivalent to 3.14 and that the diameter and height are input by the user as floating point numbers. Area of a cylinder = (2 x AreaOfEnd) + (AreaOfSide) = (2 x PI x (diameter/2)^2) + (height x PI x diameter), Volume of a cylinder = AreaOfEnd x height = (PI x (diameter/2)^2) x height.
Using a top-down hierarchical decomposition approach we can identify the following, three-level, break-down of operations:
From the above we Note that the "calculate area of a circle" operation is repeated. This indicates that the operation would be better placed at a higher level:
Inspection of the above thus indicates five distinct operations at three different levels of abstraction. We will address the identified operations using five distinct functions/procedures as follows:
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
PI | Global constant | FLOAT | 3.15 |
DIAMETER | Global variable | FLOAT | Default |
HEIGHT | Global variable | FLOAT | Default |
AREA | Global variable | FLOAT | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
RADIUS | Formal parameter | FLOAT | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
DIAMETER | Formal parameter | FLOAT | Default |
HEIGHT | Formal parameter | FLOAT | Default |
AREA | Formal parameter | FLOAT | Default |
CIRCUM | Local variable | FLOAT | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
HEIGHT | Formal parameter | FLOAT | Default |
AREA | Formal parameter | FLOAT | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
DIAMETER | Formal parameter | FLOAT | Default |
The design detail required for each of these procedures is given by the Nassi-Shneiderman charts given below.
Remember that we implement a top down analysis/design a level at a time commencing with the highest level. Where necessary calls to lower level procedures are implemented using stubs (partial implementations). The top level implementation might be as follows.
-- CYLINDER CALCULATION -- 4 August 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure CYLINDER_CALC is package FLOAT_INOUT is new FLOAT_IO(FLOAT); use FLOAT_INOUT; PI : CONSTANT FLOAT := 3.14; DIAMETER, HEIGHT, AREA : FLOAT; ------------------------------------------------------------------ -- AREA OF CIRCLE function function AREA_OF_CIRCLE return FLOAT is begin PUT_LINE("Area of circle function"); RETURN(1.0); end AREA_OF_CIRCLE; ------------------------------------------------------------------ -- AREA OF CYLINDER procedure procedure AREA_OF_CYLINDER is begin PUT_LINE("Area of cylinder procedure"); end AREA_OF_CYLINDER; ------------------------------------------------------------------ -- VOLUME OF CYLINDER procedure procedure VOLUME_OF_CYLINDER is begin PUT_LINE("Volume of cylinder procedure"); end VOLUME_OF_CYLINDER; ------------------------------------------------------------------ -- TOP LEVEL PROCEDURE begin -- Input data PUT_LINE("Input diameter: "); GET(DIAMETER); PUT_LINE("Input height: "); GET(HEIGHT); PUT(DIAMETER); PUT(HEIGHT); NEW_LINE; -- Calculation AREA := AREA_OF_CIRCLE; PUT("Area of circle is: "); PUT(AREA,FORE=>3,AFT=>4,EXP =>0); NEW_LINE; AREA_OF_CYLINDER; VOLUME_OF_CYLINDER; end CYLINDER_CALC;
Some comments:
package PACKAGE_NAME is new TEMPLATE_NAME(T); use PACKAGE_NAME;
On completion of this level-1 implementation a test run should be undertaken. Given that we do nothing with the input values at this stage there is no need to use test cases yet. However, we should ensure that the code compiles and, when executed, produces the output we would expect. In the above case the output would be as follows (given diameter and height inputs of 5.0 and 10.0):
kuban-293 $ cylinder_calc Input diameter: 5.0 Input height: 10.0 5.00000000000000E+00 1.00000000000000E+01 Area of circle function Area of circle is: 1.0000 Area of cylinder procedure Volume of cylinder procedureWe can now proceed to the next level in the implementation. In fact, given that the third level is somewhat trivial, we will implement the second and third levels together:
-- CYLINDER CALCULATION -- 4 August 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure CYLINDER_CALC is package FLOAT_INOUT is new FLOAT_IO(FLOAT); use FLOAT_INOUT; PI: CONSTANT FLOAT := 3.14; DIAMETER, HEIGHT, AREA: FLOAT; ----------------------------------------------------- -- AREA OF CIRCLE function function AREA_OF_CIRCLE(RADIUS: FLOAT) return FLOAT is begin RETURN(PI*RADIUS**2); end AREA_OF_CIRCLE; ----------------------------------------------------- -- AREA OF CYLINDER procedure procedure AREA_OF_CYLINDER(DIAMETER, HEIGHT, AREA: FLOAT) is CIRCUM: FLOAT; --------------------------------------------- -- CIRCUMFERENCE OF CIRCLE function function CIRCUM_OF_CIRCLE (DIAMETER: FLOAT) return FLOAT is begin RETURN(PI*DIAMETER); end CIRCUM_OF_CIRCLE; --------------------------------------------- begin CIRCUM:= CIRCUM_OF_CIRCLE(DIAMETER); PUT("Area of cylinder is: "); PUT(AREA*2.0+CIRCUM*HEIGHT,FORE=>3, AFT=>4,EXP =>0); NEW_LINE; end AREA_OF_CYLINDER; ----------------------------------------------------- -- VOLUME OF CYLINDER procedure procedure VOLUME_OF_CYLINDER(HEIGHT, AREA: FLOAT) is begin PUT("Volume of cylinder is: "); PUT(AREA*HEIGHT,FORE=>3,AFT=>4, EXP =>0); NEW_LINE; end VOLUME_OF_CYLINDER; ----------------------------------------------------- -- TOP LEVEL procedure begin -- Input data PUT_LINE("Input diameter: "); GET(DIAMETER); PUT_LINE("Input height: "); GET(HEIGHT); -- Calculation AREA := AREA_OF_CIRCLE(DIAMETER/2.0); AREA_OF_CYLINDER(DIAMETER, HEIGHT, AREA); VOLUME_OF_CYLINDER(HEIGHT, AREA); end CYLINDER_CALC;
Some points to note about the above code:
TEST CASE | EXPECTED RESULT | ||
---|---|---|---|
DIAMETER | HEIGHT | AREA | VOLUME |
0.0 | 0.0 | 0.0000 | 0.0000 |
0.0 | 10.0 | 0.0000 | 0.0000 |
0.0 | -10.0 | 0.0000 | 0.0000 |
5.0 | 0.0 | 39.2500 | 0.0000 |
5.0 | 10.0 | 196.2500 | 196.2500 |
5.0 | -10.0 | -117.7500 | -196.2500 |
-5.0 | 0.0 | -39.2500 | 0.0000 |
-5.0 | 10.0 | -117.75 | 196.2500 |
-5.0 | -10.0 | 196.2500 | -196.2500 |
Arithmetic testing Test using all possible combinations of negative, positive and zero input values for the DIAMETER and HEIGHT user inputs as shown in the given table (right). Note that the code allows input of negative numbers. This is likely to be undesirable and thus a return to the requirements specification should be instigated and adjustments made in the light of the procurers wishes with respect to negative results.
Data validation testing Provide input data with incorrect syntax, both blatant and subtle. Suggested test cases given below. The '*' symbol indicates that we do not expect to input a second value as we expect the code to fail.
TEST CASE | EXPECTED RESULT | ||
---|---|---|---|
DIAMETER | HEIGHT | AREA | VOLUME |
5 | * | FLOAT_INPUT_ERROR_PERIOD_NOT_READ | |
5.e | * | FLOAT_INPUT_ERROR_PERIOD_NOT_READ | |
5.0 | 10 | FLOAT_INPUT_ERROR_PERIOD_NOT_READ | |
5.0 | 1e.0 | FLOAT_INPUT_ERROR_PERIOD_NOT_READ |
Example Problem Cylinder Calculation Report.