Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 7 Introduction to Procedures. So far, all programs written in such way that all subtasks are integrated in one single large program. There is.

Similar presentations


Presentation on theme: "Chapter 7 Introduction to Procedures. So far, all programs written in such way that all subtasks are integrated in one single large program. There is."— Presentation transcript:

1 Chapter 7 Introduction to Procedures

2 So far, all programs written in such way that all subtasks are integrated in one single large program. There is no way to code, verify and test each subtask independently before combining them to the final program. Fortran has a special mechanism to do so. Each subtask can be coded as a separate program unit called external procedure which can be compiled and tested independently. FORTRAN External Procedures: –Subroutines Can be invoked using CALL statement They can return multiple results through calling arguments –Functions Can be invoked by directly using them in expression They return single value that is then used in the expression Advantages of procedures: 1.Independent testing of subtasks 2.Reusable code 3.Isolation from unintended effects Introduction to Procedures

3 Subroutine is a FORTRAN procedure that is invoked by naming it in CALL statement and that retrieves its input values and return its results through an argument list. It is an independent program that starts with SUBROUTINE and ends with END SUBROUTINE The general form of subroutine (similar to program organization) SUBROUTINE sub_name (argument_list) … ( Declaration section) … (Execution section) … RETURN END SUBROUTINE [sub_name] Subroutines Beginning END Optional Standard FORTRAN name Dummy arguments: variables or arrays passed from program Optional If we need to return before END similar to STOP, END Program

4 It is compiled independently away from the program and any other subroutine. When a program call the subroutine, the execution of the program will suspend and the procedure will execute till it reach RETURN or END SUBROUTINE and the program then resumes. Any executable program can call a subroutine including another subroutine. Subroutines

5 Calling a subroutine Place a CALL statement in the calling program’s code. CALL sub_name (argument_list) The order and type of the actual arguments match the order and type of dummy arguments in the declared subroutine.

6 Example-1 Write a program that calculates the hypotenuse of right triangle. The user should enter the first and second sides (x, y) and the program calculates and print the hypotenuse (z) x y z PROGRAM mainProgram IMPLICIT NONE REAL :: x, y, z WRITE (*,*) 'Enter first value: ' READ (*,*) x WRITE (*,*) 'Enter second value: ' READ(*,*) y CALL calculate(x, y, z) WRITE (*,*) 'Result: ', z END PROGRAM SUBROUTINE calculate ( first, second, output) IMPLICIT NONE REAL, INTENT(IN) :: first, second REAL, INTENT(OUT) :: output output = SQRT(first**2 + second**2) RETURN END SUBROUTINE PROGRAM mainProgram IMPLICIT NONE REAL :: x, y, z WRITE (*,*) 'Enter first value: ' READ (*,*) x WRITE (*,*) 'Enter second value: ' READ(*,*) y z = SQRT(x**2 + y**2) WRITE (*,*) 'Result: ', z END PROGRAM You can remove RETURN

7 INTENT Attribute INTENT(IN) Dummy argument is used to pass input data to subroutine only. INTENT(OUT) Dummy argument is used to return result to the calling program only. INTENT(INOUT) or INTENT(IN OUT) Dummy argument is used to both pass input data to subroutine and to return result to the calling program. You need to specify INTENT type for each argument but not for local variables of the subroutine. This will help the compiler to know what is expected for each argument and easily discover errors. REAL, INTENT(IN) :: in in = 3 [ERROR]

8 Example-2 PROGRAM mainProgram IMPLICIT NONE INTEGER, PARAMETER:: max_Size =10 INTEGER :: i, j REAL, DIMENSION (max_Size) :: dat REAL :: temp Write (*,*) 'Enter DATA set (', max_Size,' values) :' WRITE (*,*) DO i=1, max_Size READ (*,*) dat(i) END DO DO i=max_Size, 1, -1 DO j=2, i IF (dat(j-1) > dat(j)) THEN temp = dat(j-1) dat(j-1) = dat(j) dat(j) = temp ENDIF END DO WRITE (*,*) ' Sorted data: ' DO i=1, max_Size WRITE (*,*) dat(i) END DO END PROGRAM PROGRAM mainProgram IMPLICIT NONE INTEGER, PARAMETER:: max_Size =10 INTEGER :: i REAL, DIMENSION (max_Size) :: dat Write (*,*) 'Enter DATA set (', max_Size,' values) :' WRITE (*,*) DO i=1, max_Size READ (*,*) dat(i) END DO CALL sortArray(dat, max_Size) WRITE (*,*) ' Sorted data: ' DO i=1, max_Size WRITE (*,*) dat(i) END DO END PROGRAM SUBROUTINE sortArray (array, arrSize) IMPLICIT NONE INTEGER, INTENT (IN):: arrSize REAL, DIMENSION(arrSize), INTENT(INOUT) :: array INTEGER :: i, j REAL :: temp DO i=arrSize, 1, -1 DO j=2, i IF (array(j-1) > array(j)) THEN temp = array(j-1) array(j-1) = array(j) array(j) = temp ENDIF END DO END SUBROUTINE Sort data in array

9 Variable passing in FORTRAN Pass-by-Reference –The program passes a pointer to the memory location of actual arguments in the list which are going to be used by the subroutine to get the values of the dummy arguments. –So, pointers are sent to the subroutine not values. –Actual arguments should match the dummy arguments in number, type, and order

10 Errors PROGRAM test REAL :: a, b, sum REAL :: c READ (*,*) a, b, c CALL adding (a, b, c) WRITE (*,*) 'sum : ', sum END PROGRAM SUBROUTINE adding (x1, x2, x3, x4) REAL, INTENT(IN) :: x1, x2 INTEGER, INTENT(IN) :: x3 REAL, INTENT(OUT) :: x4 WRITE (*,*) x1, ' ', x2,' ', x3 x4 = X1 + X2 + X3 END SUBROUTINE ________________________________ Input : Output: sum : E+09 ___________________ Wrong: Number of arguments does not match PROGRAM test REAL :: a, b, sum REAL :: c READ (*,*) a, b, c CALL adding (a, b, c, sum) WRITE (*,*) 'sum : ', sum END PROGRAM SUBROUTINE adding (x1, x2, x3, x4) REAL, INTENT(IN) :: x1, x2 INTEGER, INTENT(IN) :: x3 REAL, INTENT(OUT) :: x4 WRITE (*,*) x1, ' ', x2,' ', x3 x4 = X1 + X2 + X3 END SUBROUTINE

11 Exercise-1 Write a subroutine that takes three real values, add them, and return the sum. PROGRAM test REAL :: a, b, c, sum WRITE (*,*) ‘Enter three values: ’ READ (*,*) a, b, c CALL adding (a, b, c, sum) WRITE (*,*) 'sum : ', sum END PROGRAM SUBROUTINE adding (x1, x2, x3, x4) REAL, INTENT(IN) :: x1, x2, x3 REAL, INTENT(OUT) :: x4 x4 = X1 + X2 + X3 END SUBROUTINE

12 Exercise-2 Write a subroutine that accepts three real values and return the maximum value out of the three. Don’t use the function MAX. PROGRAM test REAL :: a, b, c, maxValue WRITE (*,*) 'Enter three values: ' READ (*,*) a, b, c CALL getMax (a, b, c, maxValue) WRITE (*,*) '‘Largest Value : ', maxValue END PROGRAM SUBROUTINE getMax (x1, x2, x3, x4) REAL, INTENT(IN) :: x1, x2, x3 REAL, INTENT(OUT) :: x4 x4=x1 IF(x2>x4) THEN x4=x2 ENDIF IF(x3>x4) THEN x4=x3 ENDIF END SUBROUTINE

13 Exercise-3 Write a subroutine that accepts three real values and return the minimum value out of the three. Don’t use the function MIN. PROGRAM test REAL :: a, b, c, maxValue WRITE (*,*) 'Enter three values: ' READ (*,*) a, b, c CALL getMax (a, b, c, maxValue) WRITE (*,*) '‘Largest Value : ', maxValue END PROGRAM SUBROUTINE getMax (x1, x2, x3, x4) REAL, INTENT(IN) :: x1, x2, x3 REAL, INTENT(OUT) :: x4 x4=x1 IF(x2

14 Exercise-4 Write a subroutine that swap the values of two variables. PROGRAM test REAL :: a, b WRITE (*,*) 'Enter two values: ' READ (*,*) a, b WRITE (*,*) ' a : ', a, ' b : ', b CALL swap (a, b) WRITE (*,*) ' a : ', a, ' b : ', b END PROGRAM SUBROUTINE swap (a,b) REAL, INTENT(INOUT) :: a, b REAL :: temp temp = a a = b b = temp END SUBROUTINE

15 Passing Arrays to subroutine All what is needed is to send pointer to the memory location of the first element of the array. However, the subroutine also needs to know the size of the array in order to perform operations and make sure indexes stay within bounds. There are three ways to do so: 1.Explicit-Shape dummy array 2.Assumed-Shape dummy array 3.Assumed-size dummy array

16 Explicit-Shape Dummy Array Pass the bounds and dimensions of the array as arguments to the subroutine, then the array will be declared accordingly. This allow the bound checker in most of FORTRAN compiler to detect out-of-bound errors. In this method, since the shape and bounds are known, whole operations and array subsections can be used. SUBROUTINE getNewData (dat1, dat2, n) INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(OUT) :: dat2 REAL, Dimension (n), INTENT(IN) :: dat1 INTEGER :: i DO i=1,n dat2(i)=dat1(i)+dat1(i)**2 END DO END SUBROUTINE SUBROUTINE getNewData (dat1, dat2, n) INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(OUT) :: dat2 REAL, Dimension (n), INTENT(IN) :: dat1 INTEGER :: i dat2=dat1+dat1**2 END SUBROUTINE SUBROUTINE getNewData (dat1, dat2, n) INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(OUT) :: dat2 REAL, Dimension (n), INTENT(IN) :: dat1 INTEGER :: i dat2(1:n)=dat1(1:n)+dat1(1:n)**2 END SUBROUTINE

17 Assumed-Shape Dummy Array Shape is known rather than bounds. Declared using colon as placeholder for subscripts of the arrays The subroutine should have an explicit interface and no need to pass the array size or bounds to it. (uses modules) Whole array operations and subsection can be used in this type MODULE test CONTAINS SUBROUTINE getNewData (dat1, dat2) REAL, Dimension (:), INTENT(OUT) :: dat2 REAL, Dimension (:), INTENT(IN) :: dat1 dat2=dat1+dat1**2 END SUBROUTINE END MODULE

18 Assumed-Size Dummy Array Declare the size of the array as (*) assumed size Actual length not known by the compiler Bounds checking, whole array operations and array sections does not work here. This was in old FORTRAN, it should never be used in new programs SUBROUTINE getNewData (dat1, dat2, n) INTEGER, INTENT(IN) :: n REAL, Dimension (*), INTENT(OUT) :: dat2 REAL, Dimension (*), INTENT(IN) :: dat1 DO i=1,n dat2(i)=dat1(i)+dat1(i)**2 END DO END SUBROUTINE n is not the array size. It represent how many elements should be involved in the operation

19 Exercise-5 Write a subroutine that accept array and return the sum of all its elements. PROGRAM test IMPLICIT NONE INTEGER, Parameter :: maxSize=5 REAL :: sum REAL, DIMENSION(maxSize) :: arr=(/2., -1., 5., 10., 0./) CALL sumAll (arr, maxSize, sum) WRITE(*,*) ' sum of all values: ', sum END PROGRAM SUBROUTINE sumAll (dat, n, total) INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(IN) :: dat REAL, INTENT(OUT) :: total INTEGER :: i total=0 DO i=1,n total=total+dat(i) END DO END SUBROUTINE

20 Exercise-6 Write a subroutine that find the maximum value in an array (don’t use MAX function). PROGRAM test IMPLICIT NONE INTEGER, Parameter :: maxSize=5 REAL :: maxValue REAL, DIMENSION(maxSize) :: arr=(/2., -1., 5., 10., 0./) CALL getMax (arr, maxSize, maxValue) WRITE(*,*) ' maximum values: ', maxValue END PROGRAM SUBROUTINE getMax (dat, n, num) INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(IN) :: dat REAL, INTENT(OUT) :: num INTEGER :: i num=dat(1) DO i=2,n IF (dat(i)>num) THEN num = dat(i) END IF END DO END SUBROUTINE

21 Exercise-7 Write a subroutine that find the minimum value in an array (don’t use MIN function). PROGRAM test IMPLICIT NONE INTEGER, Parameter :: maxSize=5 REAL :: maxValue REAL, DIMENSION(maxSize) :: arr=(/2., -1., 5., 10., 0./) CALL getMax (arr, maxSize, maxValue) WRITE(*,*) ' maximum values: ', maxValue END PROGRAM SUBROUTINE getMax (dat, n, num) INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(IN) :: dat REAL, INTENT(OUT) :: num INTEGER :: i num=dat(1) DO i=2,n IF (dat(i)

22 Passing Character Variables to Subroutine The length of the character variable is declared with (*). It is not necessary to know the length in subroutine. When the subroutine is called the length of the dummy argument will be the length of the actual argument in the program. However, you can tell the size of the character at run time using the function LEN. SUBROUTINE sampleSUB (name) CHARACTER(len=*), INTENT(IN) :: name WRITE(*,*) ‘The length of the received name is: ’, LEN(name) END SUBROUTINE

23 Error Handling in Subroutine SUBROUTINE getRES (a, b, res) IMPLICIT NONE REAL, INTENT(IN) :: a, b REAL, INTENT(OUT) :: res REAL :: temp temp = a -b res = SQRT(temp) END SUBROUTINE What does this subroutine do? What is the output if a = 1, b = 2 ? Run time error: res = -NaN Rewrite it to avoid this problem. SUBROUTINE getRES (a, b, res) IMPLICIT NONE REAL, INTENT(IN) :: a, b REAL, INTENT(OUT) :: res REAL :: temp temp = a-b IF (temp>=0) THEN res = SQRT(temp) ELSE WRITE(*,*) 'Square root of negative value in subroutine getRes' STOP ENDIF END SUBROUTINE First solution: when square root of negative values is requested print an error and stop the program before returning form subroutine. The main program looses all data that are processed before calling the subroutine. Is there a better way? SUBROUTINE getRES (a, b, res, error) IMPLICIT NONE REAL, INTENT(IN) :: a, b REAL, INTENT(OUT) :: res INTEGER, INTENT(OUT) :: error REAL :: temp temp = a-b IF (temp>=0) THEN res = SQRT(temp) error = 0 ELSE res = 0 error = 1 ENDIF END SUBROUTINE Never use STOP in any subroutine. Add an error flag that indicates the situation when the subroutine return wrong values and pass it to the main program. After returning from the subroutine, the program should check the flag and display error message for the user.

24 Program Design Write a program that accepts real values from the user and store them in 1-D array. The user first should be asked to enter the size of the data set he needs to enter. Then, he will be asked to enter the values. Your program should make statistics on the data that are stored in the array. The statistics will include: 1.Find the max value and its location in the array 2.Find the min value and its location in the array 3.Calculate the average of all values 4.Find the median 5.Calculate the standard deviation For each one of the above subtasks write a subroutine. The main program will just accept the user inputs, store them in an array and call these five subroutines to get the results and print them to the user.

25

26 Sharing Data Using Modules Programs, Subroutine and Functions can exchange data through modules in addition to argument list. Module is a separately compiled program unit that contains the definitions and initial values of the data we wish to share between program units. It provides a way to share data between program units. Modules are especially useful for sharing large volumes of data among many program and procedure units.

27 Module Construct MODULE module_name IMPLICIT NONE SAVE INTEGER, PARAMETER :: num_Vals = 5 REAL, DIMENSION(num_Vals) :: values END MODULE Beginning END Declaration of the data to be shared

28 Any program unit can make use of that share data it contains the command USE module_name The USE command must be the first command after the program name or subroutine name. USE association is the process of accessing information in a module using the USE statement Using Modules

29 Example - 3 MODULE module_name IMPLICIT NONE SAVE INTEGER, PARAMETER :: num_Vals = 5 REAL, DIMENSION(num_Vals) :: values END MODULE PROGRAM test USE module_name IMPLICIT NONE values=(/1, 2, 3, 4, 5/) WRITE (*,*) values END PROGRAM SUBROUTINE display USE module_name IMPLICIT NONE WRITE (*,*) values END SUBROUTINE

30 Example - 4 MODULE module_name IMPLICIT NONE SAVE INTEGER, PARAMETER :: num_Vals = 5 REAL, DIMENSION(num_Vals) :: values=(/1,2,3,4,5/) END MODULE PROGRAM test IMPLICIT NONE CALL display END PROGRAM SUBROUTINE display USE module_name IMPLICIT NONE WRITE (*,*) values END SUBROUTINE

31 Random Number Generator Random number generator is a procedure that return different numbers that seem to be random. One simple random number generator uses the following equation N i+1 = MOD( 8121 n i , ) The random number ran i = n i / n 0 is call the seed of the sequence which should be entered by the user so the sequence vary from run to another. Write a subroutine randomNum that generates and return a single number ran based on the above equations. Another subroutine (seed) should be called to get the seed value n 0.

32 Random Number Generator PROGRAM randomGenerator IMPLICIT NONE INTEGER :: n0 REAL :: num WRITE (*,*) 'Enter the seed value: ' READ (*,*) n0 CALL seed(n0) CALL randomNum(num) WRITE (*,*) num END PROGRAM SUBROUTINE randomNum(ran) USE ranValue IMPLICIT NONE REAL, INTENT(OUT):: ran n = MOD(8121*n+28411, ) ran = REAL(n)/ END SUBROUTINE SUBROUTINE seed(inSeed) USE ranValue IMPLICIT NONE INTEGER, INTENT(IN):: inSeed n = ABS(inSeed) END SUBROUTINE MODULE ranValue IMPLICIT NONE SAVE INTEGER :: n END MODULE

33 PROGRAM randomGenerator IMPLICIT NONE INTEGER :: n0 REAL :: num WRITE (*,*) 'Enter the seed value: ' READ (*,*) n0 CALL seed(n0) CALL randomNum(num) WRITE (*,*) num END PROGRAM SUBROUTINE randomNum(ran) USE ranValue IMPLICIT NONE REAL, INTENT(OUT):: ran n = MOD(8121*n+28411, ) ran = REAL(n)/ END SUBROUTINE SUBROUTINE seed(inSeed) USE ranValue IMPLICIT NONE INTEGER, INTENT(IN):: inSeed n = ABS(inSeed) END SUBROUTINE MODULE ranValue IMPLICIT NONE SAVE INTEGER :: n END MODULE Full Program Now, modify the main program so that it prints 10 random numbers. Then, make it generates 1000 numbers and calculate their average. PROGRAM randomGenerator IMPLICIT NONE INTEGER :: n0, i REAL :: num, sum=0, Avg WRITE (*,*) 'Enter the seed value: ' READ (*,*) n0 CALL seed(n0) WRITE (*,*) ' 10 random numbers : ' DO i=1, 10 CALL randomNum(num) WRITE (*,*) num END DO DO i=1, 1000 CALL randomNum(num) sum = sum +num END DO Avg = sum / 1000 WRITE (*,*) ' The average of 1000 random numbers is: ', Avg END PROGRAM

34 FORTRAN FUNCTION FORTRAN Function is a procedure that returns single output which can be, number, logical value, character string or an array. In contrast to routines, functions can be used and combined with expressions. Function types: –Intrinsic functions Built into the FORTRAN language (e.g. SIN(x), MAX(a,b)) –User-defined functions (function subprograms) Defined by a programmer to meet specific needs not addressed by intrinsic functions and they are used in expressions like intrinsic function.

35 Function Construct FUNCTION functionName (argument_List) … (Declaration Section must declare type of functionName) … (Execution section) functionName = expr RETURN END FUNCTION [ functionName ] FUNCTION myMax (a, b) IMPLICIT NONE REAL :: myMax REAL, INTENT(IN) :: a, b IF(a>=b) THEN myMax = a ELSE myMax=b END IF END FUNCTION Beginning END Optional Standard FORTRAN name Dummy arguments: variables or arrays passed from program. Can be blank but with parenthesis Optional If we need to return before END The return value

36 Declaring Function Type FUNCTION myMax(a,b) REAL :: myMax FUNCTION myMax (a, b) IMPLICIT NONE REAL :: myMax REAL, INTENT(IN) :: a, b IF(a>=b) THEN myMax = a ELSE myMax=b END IF END FUNCTION REAL FUNCTION myMax (a, b) IMPLICIT NONE REAL, INTENT(IN) :: a, b IF(a>=b) THEN myMax = a ELSE myMax=b END IF END FUNCTION OR REAL FUNCTION myMax(a,b)

37 Exercise-8 Write a program that call the function quadf that calculates and returns the value of the quadratic equation. In the main program the user will be asked to enter the three coefficients a, b, c and the evaluation value x. All of these four values will be sent as arguments to the function quadf. Finally, the program will print the result returned by the function.

38 FUNCTION quadf(x,a,b,c) IMPLICIT NONE REAL :: quadf REAL, INTENT(IN) :: x,a,b,c quadf=a*x**2+b*x+c END FUNCTION REAL FUNCTION quadf(x,a,b,c) IMPLICIT NONE REAL, INTENT(IN) :: x,a,b,c quadf=a*x**2+b*x+c END FUNCTION PROGRAM quadraticFunction IMPLICIT NONE REAL :: quadf REAL :: a, b, c, x, f WRITE (*,*) 'Enter the three coefficients a,b,c : ' READ (*,*) a,b,c WRITE (*,*) 'Enter the evaluation value x: ' READ (*,*) x f = quadf(x, a, b, c) WRITE (*,*) 'The quadratic result: ', f END PROGRAM

39 Unintended Side Effects in Functions Side effect happen when the function change the values of the input arguments in the program. The function should produce single output and it should have no side effects. It should never modify its input arguments. If you need a function that produce more than one result then, use subroutine instead. Always declare input arguments with INTENT(IN) to avoid side effects.

40 Exercise-9 The sinc function is defined by the equation: sinc(x)=sin(x)/x It is easy to implement but consider x equal or very close to zero. Modify the equation to be: IF |x|> Epsilon sinc(x)=sin(x)/x Else sinc=1 Epsilon is very small real number that is chosen to ensure that the division does not cause divide by zero. A good value of Epsilon is 1.0E-30

41 PROGRAM getSINC IMPLICIT NONE REAL :: sinc REAL :: x WRITE (*,*) 'Enter a number to evaluate with SINC : ' READ (*,*) x WRITE(*,*) 'THe value is: ', sinc(x) END PROGRAM REAL FUNCTION sinc(x) IMPLICIT NONE REAL, PARAMETER :: eps=1.0E-30 REAL, INTENT(IN) :: x IF (ABS(x)>eps) THEN sinc=SIN(x)/x ELSE sinc=1 END IF END FUNCTION

42 Tutorial Write a subroutine to compute the average of all the elements in a matrix. Use a SUBROUTINE AND A MODULE within a program to ask the user for a matrix, and compute its average. PROGRAM tutorial_on_subroutines USE tut IMPLICIT NONE INTEGER :: i, j WRITE(*,*) 'Enter the elements of the matrix A (3x3)' READ (*,*) A CALL find_mean WRITE (*,*) 'The mean of your matrix = ', A_mean END PROGRAM MODULE tut IMPLICIT NONE REAL, DIMENSION (3,3) :: A REAL:: A_mean END MODULE SUBROUTINE find_mean USE tut IMPLICIT NONE INTEGER :: i, j REAL :: total=0.0 DO i=1,3 DO j=1,3 total = total + A(i,j) END DO A_mean = total / 9.0 END SUBROUTINE Add one more subroutine to find the maximum value in the matrix and its location


Download ppt "Chapter 7 Introduction to Procedures. So far, all programs written in such way that all subtasks are integrated in one single large program. There is."

Similar presentations


Ads by Google