CH/S6CS/Sept. 2004 SUBPROGRAM PROCEDURE One approach to solving a complex problem is to divide it into subproblems and then solve the simpler subproblems. These subproblems can in turn be divided repeatedly into smaller problems until these smaller problems are easily solved. ( Top-down approach / Divide and Conquer ) In Pascal, the main program solves the main problem. Solutions to the subproblems are provided by subprograms, known as procedures or functions . A procedure must begin with the reserved word procedure followed by an identifier, i.e. the procedure name. The structure of a procedure is very similar to that of an entire Pascal program. It may have its own type constant and variable declarations and even . ( ) Syntax diagram for parameter list and procedure: Parameter list: ; , ( identifier : type identifier ) parameter list ; VAR Procedure: PROCEDURE identifier e.g. Here is a simple example of procedure, procedure computearea(base, altitude : real; var area : real); { Compute area of triangle from base and altitude } begin area := 0.5 * altitude * base end; Once a procedure is defined, a Pascal statement consisting of procedure name is executed as " calling ", or " involving " the procedure, resulting in the execution of the statement in the procedure itself. The procedure in the above example is invoked by the following statement, computearea(2,1,result); Criteria of using a procedure, i. When a sequence of statement is used several times in different places in the program. ii. Enhance readability. iii. Each procedure can be written by different programmers, because each procedure can be totally independent of the others. Group programming is possible. iv. Above all, it makes the program more structured . PARAMETER Procedures are most effective when they are self-contained modules. ... Each procedure can be tested independently. SUBPROGRAM and independent program page 1 CH/S6CS/Sept. 2004 So, using fewer global variables . An alternative and better solution to using global variables: using parameters . Parameters enable procedures to manipulate different sets of values and so the same procedure can be used several times in the same program. e.g. altitude , base and area in the sample procedure computearea on p.1. The parameters listed in the procedure header, i.e. altitude, base and area, are called formal parameter . They serve as placeholder for the actual values supplied when the procedure is invoked. Two types of parameters i. ii. ** Value parameters. (passing by value) a. As input parameters which only accept values from the calling routine. b. Followed by a colon and the data type of the parameter. c. Value parameters of the same type are separated by a comma and the list is ended by a semicolon. d. In the above example, "altitude" and "base" are value parameters. Variable parameters. (passing by reference) a. As both input and output parameter. b. The variable parameter begins with the reserved word c. In the above example, area is the only variable parameter. var . Some programming languages allow passing parameters by value-result, i.e. copying the values into the formal parameters before invoking the procedure and copying the value back to actual parameter after procedure execution. How does the computer supply and retrieve the actual values for the formal parameters in the main program? procedure circle (radius : real; var area, circum : real); const pi = 3.14159; begin area := pi * sqrt(radius); circum := 2 * pi * radius; end; (* main program *) begin : : (* procedure invocation *) circle ( 5, area, circumference) : : end. i. A procedure with a parameter list is invoked by the main program or calling procedure in a statement of the program identifier followed by a list of values supplied to the parameter, inside parenthesises. These values are called actual parameters. SUBPROGRAM page 2 CH/S6CS/Sept. 2004 ii. The order of the actual parameters in the procedure invocation must be the same as the order of the formal parameters in the procedure header. iii. Execution aspects for parameter passing : a. Value parameter: A copy of the actual parameter’s value is stored in a new location in memory and give the name of the corresponding formal parameter. 1234 5 radius = 5678 5 Fig. 2a b. Variable parameter: The original memory location (reference) for each is given an additional name (an alias), as specified by the corresponding formal variable parameters. circum = circumference = 1234 999 Fig. 2b Remember that: i. Those actual parameters corresponding to the value parameters of the procedure header must have a value before the procedure is invoked. So it can be a variable, a constant or even an expression. ii. Those actual parameters corresponding to the variable parameters of the procedure header must be specified as variables . Local and Global Variables In case that all the variables in a procedure are shared with that in the main programmes, no parameter is necessary. These variables are called global variables. Global variables. Variables that any procedure can reference them. Local variables. Variables declared in a procedure and known only within that procedure and procedures inside it. If the name of a global variable is the same as a local variable or a formal parameter, the local variable or the formal parameter will have a precedence over the global variable in the procedure, but it will be unknown in the calling program. Nested Procedures and Scope Rule Procedures within procedures The scope of an identifier is that portion of the program where the identifier is known. For instance, in the above sample procedure, the scope of the local variable inchar in procedure dollar is only inside the procedure dollar. On the other hand, the variable test is a global variable known to procedures dollar and wage. Formal parameters have the same scope rule to the local variables, e.g. the formal parameter flag is local to the procedure wage. Procedure names follow the same scope rule as that of variable names. SUBPROGRAM page 3 CH/S6CS/Sept. 2004 Consider the following example, procedure outer (input, output); procedure inner1 (x, y: integer); begin end; procedure inner2 (var a: integer); procedure innermost (var x, y: integer); begin end; begin end; begin end; i. Procedure inner2 can call procedure inner1 since the procedure inner2 comes after procedure inner1 , however, procedure inner1 cannot call procedure inner2 . ii. Procedure innermost can also call procedure inner2. iii. Procedure innermost cannot be called by any procedure outside the procedure(s) containing procedure inner2 , e.g. inner1 . ** Remember that: Global variables should not be changed by a procedure (side effect). Procedures should be self-contained independent modules. FUNCTION Functions are subprograms that return a single value. There are two kinds of functions in Pascal: standard (or built-in) or user-defined. User-defined functions Similar to procedures except that the purpose of a function is to return only one value to the main program or procedure from which it was called. The function looks similar to a procedure. The reserved word FUNCTION followed by the function identifier and the parameter list. This is followed by a colon and the type identifier that specifies the type of the value that the function result will have. Syntax diagram for function header: FUNCTION identifier parameter list : type identifier ; Examples: i. SUBPROGRAM function factorial (num: integer): integer; var i, fact: integer begin fact := 1; if fact > 2 then for i := 2 to num do fact := fact * i; factorial := fact end; page 4 CH/S6CS/Sept. 2004 ii. function power (base: real, expo: integer): real; var i: integer; po: real; begin po := 1; if expo = 0 then po := 1 else if expo > 0 then for i := 1 to expo do po := po * base else for i := 1 to -1 * expo do po := po / base; power := po end; Function invocation As with procedures, a function invocation requires that the order and data type of the actual parameters match exactly with those of the formal parameters. A function is invoked by writing their name and parameter list in an expression, e.g. x := power(2.0, 3) / 3; nCr := factorial(n) / factorial(n-r) / factorial(r); ** Note that: i. Inside a user-defined function, the function name must appear on the left hand side of at least one assignment statement inside the function itself to communicate the result of the function to the point of invocation. ii. In the calling module the function names appear only in the right hand side. (It gives value but does not accept value through the function names.) iii. There are also nested functions and the function names also have scope rules as those on procedure names. Standard Function and Procedure Standard functions are predefined functions available in standard Pascal (in the system library). Function Definition Type of parameter Type of result abs(x) arctan(x) chr(x) cos(x) eof(x) eoln(x) exp(x) The absolute value of x The arctangent of x The character represented by ordinal number x The cosine of x (x in radians) Test if an end of file has been detected Test if an end of line has been detected ex, where e = 2.71828… The natural algorithm of x Test if x is odd or even The ordinal number of x The predecessor of x The rounded value of x to the nearest integer The sine of x (x in radians) The square root of x (x > 0) The successor of x The truncated value of x Integer or real Integer or real Integer Integer or real File File Integer or real Integer or real Integer Any ordinal Any ordinal Real Integer or real Integer or real Any ordinal Real Same as x Real Char Real Boolean Boolean Real Real Boolean Integer Same as x Integer Real Real Same as x Integer ln(x) odd(x) ord(x) pred(x) round(x) sin(x) sqrt(x) succ(x) trunc(x) SUBPROGRAM page 5 CH/S6CS/Sept. 2004 Standard procedures are predefined procedures available in standard Pascal (in the system library). Procedure Definition dispose(p) Indicates that the storage pointed to by p is available for reallocation; p becomes logically undefined. Advances file variable f so the next component of f is available for inspection in f^. Dynamically allocate storage for a variable of the type pointed to by p and assign p the address of this storage. Copy a[i], a[i+1], … to p starting with the first element of p. Append end-of-page line to text file f if necessary, and arrange for next put, write, or writeln referencing f to place output on a new page. Append f^ as a new component of f; f^ becomes undefined Read, and possibly perform conversions of textual data, from file variable f, assigning values to variables named to list. Same as read, except advances past next end of line on text files as last operation. Prepare for reading from file variable f; places f in input, or inspection, mode. Prepare for writing or display on file variable f; places f in output mode. Copy elements of p starting with first element to u[i], u[i+1], … Write, possibly with conversion to textual form, the value of each expression in list to be in file f Same as write, except appends end of line to text files as last operation. get(f) new(p) pack(u, i, p) page(f) put(f) read(f, list) readln(f, list) reset(f) rewrite(f) unpack(p, u, i) write(f, list) writeln(f, list) Side Effect. A function can have variable parameters. But it will modify a global variable -- side effect Portability. We have emphasised the use of a Pascal standard because programs written in Standard Pascal can be moved from one computer system to another, using different Pascal compilers, with a minimal amount of change i.e. portable. RECURSIVE PROCEDURES AND FUNCTIONS A function or procedure that calls, or invokes, itself is called recursive. It can be quite powerful in problem solving, especially in application in advanced computer science. Recursive functions (or procedures) are quite suitable to use when a problem can be defined in terms of itself (recursively). Sample program 1. Compound Interest. A financial institution pays 12 percent annual interest at the beginning of every year on the money left there during the previous year. We wish to determine how much an initial investment of $1000 would be worth if it and the interest were left for n years. Assume an to be the amount of money accumulated at the beginning of year n. Thus, a0 = 1000 ai = 1.12 * ai-1 Here is the complete recursive function to determine the value of the investment after n years: function amount (n : integer) : real; { Recursive function to compute amount in an account at 12 percent interest with initial investment of $1000.00. } begin if n = 0 then amount := 1000.0 else amount := 1.12 * amount(n-1) end; SUBPROGRAM page 6 CH/S6CS/Sept. 2004 Then, amount(3) 1.12 * amount(2) 1.12 * amount(1) 1.12 * amount(0) 1000 ... The amount after 3 years are 1.12 * (1.12 * (1.12 * 1000)) 1405 Sample Program 2: Tower of Hanoi ‘The Tower of Hanoi’ is a game played with three poles and a set of discs, all differently sized, which fit on to the poles. Initially all the discs are on pole A , as shown below; the objective of the game is to move all the discs on to pole B . Only one disc may be moved at a time, and no disc may ever be placed above a smaller disc. Pole A Pole B Pole C Consider the more general problem of moving N discs from pole source to pole dest, using pole spare as a spare pole. This problem can be solved recursively by the following strategy: (1) move (N-1) discs from pole source to pole spare , using pole dest as a spare pole. (2) move a single disc N from pole source to pole dest . (3) move (N-1) discs from pole spare to dest, using pole spare as a spare pole. Here is the Pascal program to implement the strategy and show each move. program TowerOfHanoi (input, output); procedure move (diskno : integer; source, dest, spare : char); begin if diskno > 0 then begin move(diskno-1, source, spare, dest); writeln('Disk', diskno, ': ', source, ' -> ', dest); move(diskno-1, spare, dest, source); end; end; begin move (4,'A','B','C') end. Tips on writing recursive procedures or functions (1) There must be a stopping condition. (2) It must move closer to the stopping condition after each recursive call. SUBPROGRAM page 7 CH/S6CS/Sept. 2004 Operation Details When a procedure or function is invoked, whether recursively or not, the values of the “caller’s” local variables, constants, and address of calling point are saved on a stack. When the procedure terminates, the local values of the caller are restored from the stack. Assume that we have a program such that i. main program calls procedure A, and ii. procedure A calls procedure B. Then begin{main} A(); procedure A(); begin{main} main program’s detail procedure A’s detail B(); main’s procedure B(); begin {B} end;{B} proceudure A(); begin {A} end; {A} procedure A’s detail main program’s details Procedure A’s main’s main’s Usually, a repetitive problem can be solved by both of the two methods should be used? iteration and recursion . Then which i. In a recursive solution, a computer must keep track of each recursive call, (using the stack), and it requires a large amount of time and storage. ii. Recursion usually makes a program less readable . In general, use a recursive solution only if the solution cannot be easily translated to the equivalent iterative solution (e.g. tower of Hanoi), or if the efficiency of the recursive solution is more satisfactory. SUBPROGRAM page 8