Chapter 7 Introduction to Procedures. So far, all programs written in such way that all subtasks are...
-
Upload
kristen-silva -
Category
Documents
-
view
230 -
download
0
Transcript of Chapter 7 Introduction to Procedures. So far, all programs written in such way that all subtasks are...
• 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 subtasks2. Reusable code3. Isolation from unintended effects
Introduction to Procedures
• 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)…
RETURNEND 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
• 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
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.
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
22 yxz
PROGRAM mainProgramIMPLICIT NONEREAL :: x, y, zWRITE (*,*) 'Enter first value: 'READ (*,*) xWRITE (*,*) 'Enter second value: 'READ(*,*) yCALL calculate(x, y, z)WRITE (*,*) 'Result: ', zEND PROGRAM
SUBROUTINE calculate ( first, second, output)IMPLICIT NONEREAL, INTENT(IN) :: first, secondREAL, INTENT(OUT) :: outputoutput = SQRT(first**2 + second**2)RETURNEND SUBROUTINE
PROGRAM mainProgramIMPLICIT NONEREAL :: x, y, zWRITE (*,*) 'Enter first value: 'READ (*,*) xWRITE (*,*) 'Enter second value: 'READ(*,*) yz = SQRT(x**2 + y**2)WRITE (*,*) 'Result: ', zEND PROGRAM
You can remove RETURN
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) :: inin = 3 [ERROR]
Example-2PROGRAM mainProgramIMPLICIT NONEINTEGER, PARAMETER:: max_Size =10INTEGER :: i, jREAL, DIMENSION (max_Size) :: datREAL :: tempWrite (*,*) 'Enter DATA set (', max_Size,' values) :'WRITE (*,*)DO i=1, max_SizeREAD (*,*) dat(i)END DODO i=max_Size, 1, -1DO j=2, iIF (dat(j-1) > dat(j)) THENtemp = dat(j-1)dat(j-1) = dat(j)dat(j) = tempENDIFEND DOEND DOWRITE (*,*) ' Sorted data: 'DO i=1, max_SizeWRITE (*,*) dat(i)END DOEND PROGRAM
PROGRAM mainProgramIMPLICIT NONEINTEGER, PARAMETER:: max_Size =10INTEGER :: iREAL, DIMENSION (max_Size) :: datWrite (*,*) 'Enter DATA set (', max_Size,' values) :'WRITE (*,*)DO i=1, max_SizeREAD (*,*) dat(i)END DOCALL sortArray(dat, max_Size)WRITE (*,*) ' Sorted data: 'DO i=1, max_SizeWRITE (*,*) dat(i)END DOEND PROGRAMSUBROUTINE sortArray (array, arrSize)IMPLICIT NONEINTEGER, INTENT (IN):: arrSizeREAL, DIMENSION(arrSize), INTENT(INOUT) :: arrayINTEGER :: i, jREAL :: tempDO i=arrSize, 1, -1DO j=2, iIF (array(j-1) > array(j)) THENtemp = array(j-1)array(j-1) = array(j)array(j) = tempENDIFEND DOEND DOEND SUBROUTINE
Sort data in array
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
PROGRAM test
SUBROUTINE adding
PROGRAM testREAL :: a, b, sumINTEGER :: c...CALL adding (a, b, c, sum)...END PROGRAM
SUBROUTINE adding (x1, x2, x3, x4)REAL, INTENT(IN) :: x1, x2INTEGER, INTENT(IN) :: x3REAL, INTENT(OUT) :: x4x4 = X1 + X2 + X3END SUBROUTINE
RE
AL
INT
EG
ER
RE
AL
RE
AL
ErrorsPROGRAM testREAL :: a, b, sumREAL :: cREAD (*,*) a, b, cCALL adding (a, b, c)WRITE (*,*) 'sum : ', sumEND PROGRAM
SUBROUTINE adding (x1, x2, x3, x4)REAL, INTENT(IN) :: x1, x2INTEGER, INTENT(IN) :: x3REAL, INTENT(OUT) :: x4WRITE (*,*) x1, ' ', x2,' ', x3x4 = X1 + X2 + X3END SUBROUTINE
________________________________Input : 12.6 16.5 14.9Output: 12.6 16.5 1097754214sum : 1.09775424E+09
___________________Wrong:Number of arguments does not match
PROGRAM testREAL :: a, b, sumREAL :: cREAD (*,*) a, b, cCALL adding (a, b, c, sum)WRITE (*,*) 'sum : ', sumEND PROGRAM
SUBROUTINE adding (x1, x2, x3, x4)REAL, INTENT(IN) :: x1, x2INTEGER, INTENT(IN) :: x3REAL, INTENT(OUT) :: x4WRITE (*,*) x1, ' ', x2,' ', x3x4 = X1 + X2 + X3END SUBROUTINE
Exercise-1
Write a subroutine that takes three real values, add them, and return the sum.
PROGRAM testREAL :: a, b, c, sumWRITE (*,*) ‘Enter three values: ’READ (*,*) a, b, cCALL adding (a, b, c, sum)WRITE (*,*) 'sum : ', sumEND PROGRAM
SUBROUTINE adding (x1, x2, x3, x4)REAL, INTENT(IN) :: x1, x2, x3REAL, INTENT(OUT) :: x4x4 = X1 + X2 + X3END SUBROUTINE
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, maxValueWRITE (*,*) 'Enter three values: 'READ (*,*) a, b, cCALL getMax (a, b, c, maxValue)WRITE (*,*) '‘Largest Value : ', maxValueEND PROGRAM
SUBROUTINE getMax (x1, x2, x3, x4)REAL, INTENT(IN) :: x1, x2, x3REAL, INTENT(OUT) :: x4x4=x1IF(x2>x4) THENx4=x2ENDIFIF(x3>x4) THENx4=x3ENDIFEND SUBROUTINE
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, maxValueWRITE (*,*) 'Enter three values: 'READ (*,*) a, b, cCALL getMax (a, b, c, maxValue)WRITE (*,*) '‘Largest Value : ', maxValueEND PROGRAM
SUBROUTINE getMax (x1, x2, x3, x4)REAL, INTENT(IN) :: x1, x2, x3REAL, INTENT(OUT) :: x4x4=x1IF(x2<x4) THENx4=x2ENDIFIF(x3<x4) THENx4=x3ENDIFEND SUBROUTINE
Exercise-4
Write a subroutine that swap the values of two variables.
PROGRAM testREAL :: a, bWRITE (*,*) 'Enter two values: 'READ (*,*) a, bWRITE (*,*) ' a : ', a, ' b : ', bCALL swap (a, b)WRITE (*,*) ' a : ', a, ' b : ', bEND PROGRAM
SUBROUTINE swap (a,b)REAL, INTENT(INOUT) :: a, bREAL :: temptemp = aa = bb = tempEND SUBROUTINE
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 array2. Assumed-Shape dummy array3. Assumed-size dummy array
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) :: dat2REAL, Dimension (n), INTENT(IN) :: dat1INTEGER :: iDO i=1,ndat2(i)=dat1(i)+dat1(i)**2END DOEND SUBROUTINE
SUBROUTINE getNewData (dat1, dat2, n)INTEGER, INTENT(IN) :: n REAL, Dimension (n), INTENT(OUT) :: dat2REAL, Dimension (n), INTENT(IN) :: dat1INTEGER :: idat2=dat1+dat1**2END SUBROUTINE
SUBROUTINE getNewData (dat1, dat2, n)INTEGER, INTENT(IN) :: nREAL, Dimension (n), INTENT(OUT) :: dat2REAL, Dimension (n), INTENT(IN) :: dat1INTEGER :: idat2(1:n)=dat1(1:n)+dat1(1:n)**2END SUBROUTINE
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 testCONTAINS
SUBROUTINE getNewData (dat1, dat2)REAL, Dimension (:), INTENT(OUT) :: dat2REAL, Dimension (:), INTENT(IN) :: dat1dat2=dat1+dat1**2END SUBROUTINE
END MODULE
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) :: dat2REAL, Dimension (*), INTENT(IN) :: dat1DO i=1,ndat2(i)=dat1(i)+dat1(i)**2END DOEND SUBROUTINE
n is not the array size. It represent how many elements should be involved in
the operation
Exercise-5
Write a subroutine that accept array and return the sum of all its elements.
PROGRAM testIMPLICIT NONEINTEGER, Parameter :: maxSize=5REAL :: sumREAL, DIMENSION(maxSize) :: arr=(/2., -1., 5., 10., 0./)CALL sumAll (arr, maxSize, sum)WRITE(*,*) ' sum of all values: ', sumEND PROGRAM
SUBROUTINE sumAll (dat, n, total)INTEGER, INTENT(IN) :: nREAL, Dimension (n), INTENT(IN) :: datREAL, INTENT(OUT) :: totalINTEGER :: itotal=0DO i=1,ntotal=total+dat(i)END DOEND SUBROUTINE
Exercise-6
Write a subroutine that find the maximum value in an array (don’t use MAX function).
PROGRAM testIMPLICIT NONEINTEGER, Parameter :: maxSize=5REAL :: maxValueREAL, DIMENSION(maxSize) :: arr=(/2., -1., 5., 10., 0./)CALL getMax (arr, maxSize, maxValue)WRITE(*,*) ' maximum values: ', maxValueEND PROGRAM
SUBROUTINE getMax (dat, n, num)INTEGER, INTENT(IN) :: nREAL, Dimension (n), INTENT(IN) :: datREAL, INTENT(OUT) :: numINTEGER :: inum=dat(1)DO i=2,nIF (dat(i)>num) THENnum = dat(i)END IFEND DOEND SUBROUTINE
Exercise-7
Write a subroutine that find the minimum value in an array (don’t use MIN function).
PROGRAM testIMPLICIT NONEINTEGER, Parameter :: maxSize=5REAL :: maxValueREAL, DIMENSION(maxSize) :: arr=(/2., -1., 5., 10., 0./)CALL getMax (arr, maxSize, maxValue)WRITE(*,*) ' maximum values: ', maxValueEND PROGRAM
SUBROUTINE getMax (dat, n, num)INTEGER, INTENT(IN) :: nREAL, Dimension (n), INTENT(IN) :: datREAL, INTENT(OUT) :: numINTEGER :: inum=dat(1)DO i=2,nIF (dat(i)<num) THENnum = dat(i)END IFEND DOEND SUBROUTINE
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
Error Handling in SubroutineSUBROUTINE getRES (a, b, res)IMPLICIT NONEREAL, INTENT(IN) :: a, bREAL, INTENT(OUT) :: resREAL :: temptemp = a -bres = 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 NONEREAL, INTENT(IN) :: a, bREAL, INTENT(OUT) :: resREAL :: temptemp = a-bIF (temp>=0) THENres = SQRT(temp)ELSEWRITE(*,*) 'Square root of negative value in subroutine getRes'STOPENDIFEND 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 NONEREAL, INTENT(IN) :: a, bREAL, INTENT(OUT) :: resINTEGER, INTENT(OUT) :: errorREAL :: temptemp = a-bIF (temp>=0) THENres = SQRT(temp)error = 0ELSEres = 0error = 1ENDIFEND 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.
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 array2. Find the min value and its location in the array3. Calculate the average of all values 4. Find the median5. 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.
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.
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
• 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
Example - 3
MODULE module_nameIMPLICIT NONESAVEINTEGER, PARAMETER :: num_Vals = 5REAL, DIMENSION(num_Vals) :: valuesEND MODULE
PROGRAM testUSE module_nameIMPLICIT NONEvalues=(/1, 2, 3, 4, 5/)WRITE (*,*) valuesEND PROGRAM
SUBROUTINE displayUSE module_nameIMPLICIT NONEWRITE (*,*) valuesEND SUBROUTINE
Example - 4
MODULE module_nameIMPLICIT NONESAVEINTEGER, PARAMETER :: num_Vals = 5REAL, DIMENSION(num_Vals) :: values=(/1,2,3,4,5/)END MODULE
PROGRAM testIMPLICIT NONECALL displayEND PROGRAM
SUBROUTINE displayUSE module_nameIMPLICIT NONEWRITE (*,*) valuesEND SUBROUTINE
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
Ni+1 = MOD( 8121 ni + 28411, 134456)
• The random number rani = ni / 134456
• n0 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 n0.
Random Number GeneratorPROGRAM randomGeneratorIMPLICIT NONEINTEGER :: n0REAL :: numWRITE (*,*) 'Enter the seed value: 'READ (*,*) n0CALL seed(n0)CALL randomNum(num)WRITE (*,*) numEND PROGRAM
SUBROUTINE randomNum(ran)USE ranValueIMPLICIT NONEREAL, INTENT(OUT):: rann = MOD(8121*n+28411, 134456)ran = REAL(n)/134456END SUBROUTINE
SUBROUTINE seed(inSeed)USE ranValueIMPLICIT NONEINTEGER, INTENT(IN):: inSeedn = ABS(inSeed)END SUBROUTINE
MODULE ranValueIMPLICIT NONESAVEINTEGER :: nEND MODULE
PROGRAM randomGeneratorIMPLICIT NONEINTEGER :: n0REAL :: numWRITE (*,*) 'Enter the seed value: 'READ (*,*) n0CALL seed(n0)CALL randomNum(num)WRITE (*,*) numEND PROGRAM
SUBROUTINE randomNum(ran)USE ranValueIMPLICIT NONEREAL, INTENT(OUT):: rann = MOD(8121*n+28411, 134456)ran = REAL(n)/134456END SUBROUTINE
SUBROUTINE seed(inSeed)USE ranValueIMPLICIT NONEINTEGER, INTENT(IN):: inSeedn = ABS(inSeed)END SUBROUTINE
MODULE ranValueIMPLICIT NONESAVEINTEGER :: nEND 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 randomGeneratorIMPLICIT NONEINTEGER :: n0, iREAL :: num, sum=0, AvgWRITE (*,*) 'Enter the seed value: 'READ (*,*) n0CALL seed(n0)WRITE (*,*) ' 10 random numbers : 'DO i=1, 10CALL randomNum(num)WRITE (*,*) numEND DODO i=1, 1000CALL randomNum(num)sum = sum +numEND DOAvg = sum / 1000WRITE (*,*) ' The average of 1000 random numbers is: ', AvgEND PROGRAM
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 functionsBuilt 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.
Function Construct
FUNCTION functionName (argument_List)…(Declaration Section must declare type of functionName)…(Execution section)functionName = exprRETURNEND FUNCTION [ functionName ]
FUNCTION myMax (a , b)IMPLICIT NONEREAL :: myMaxREAL, INTENT(IN) :: a, bIF(a>=b) THENmyMax = aELSEmyMax=bEND IFEND FUNCTION
Beginning
END
Optional
Standard FORTRAN nameDummy arguments: variables or arrays
passed from program. Can be blank but with
parenthesis
Optional
If we need to return before END
The return value
Declaring Function Type
FUNCTION myMax(a,b)
REAL :: myMax
FUNCTION myMax (a , b)IMPLICIT NONEREAL :: myMaxREAL, INTENT(IN) :: a, bIF(a>=b) THENmyMax = aELSEmyMax=bEND IFEND FUNCTION
REAL FUNCTION myMax (a , b)IMPLICIT NONEREAL, INTENT(IN) :: a, bIF(a>=b) THENmyMax = aELSEmyMax=bEND IFEND FUNCTION
ORREAL FUNCTION myMax(a,b)
Exercise-8Write 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.
cbxaxxcbaquadf 2),,,(
FUNCTION quadf(x,a,b,c)IMPLICIT NONEREAL :: quadfREAL, INTENT(IN) :: x,a,b,cquadf=a*x**2+b*x+cEND 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 quadraticFunctionIMPLICIT NONEREAL :: quadfREAL :: a, b, c, x, fWRITE (*,*) 'Enter the three coefficients a,b,c : 'READ (*,*) a,b,cWRITE (*,*) 'Enter the evaluation value x: 'READ (*,*) xf = quadf(x, a, b, c)WRITE (*,*) 'The quadratic result: ', fEND PROGRAM
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.
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)/xElse 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
PROGRAM getSINCIMPLICIT NONEREAL :: sincREAL :: xWRITE (*,*) 'Enter a number to evaluate with SINC : 'READ (*,*) xWRITE(*,*) 'THe value is: ', sinc(x)END PROGRAM
REAL FUNCTION sinc(x)IMPLICIT NONEREAL, PARAMETER :: eps=1.0E-30REAL, INTENT(IN) :: xIF (ABS(x)>eps) THENsinc=SIN(x)/xELSEsinc=1END IFEND FUNCTION
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_subroutinesUSE tutIMPLICIT NONEINTEGER :: i, jWRITE(*,*) 'Enter the elements of the matrix A (3x3)'READ (*,*) ACALL find_meanWRITE (*,*) 'The mean of your matrix = ', A_meanEND PROGRAM
MODULE tutIMPLICIT NONEREAL, DIMENSION (3,3) :: AREAL:: A_meanEND MODULE
SUBROUTINE find_meanUSE tutIMPLICIT NONEINTEGER :: i, jREAL :: total=0.0DO i=1,3DO j=1,3total = total + A(i,j)END DOEND DOA_mean = total / 9.0END SUBROUTINE
Add one more subroutine to find the maximum value in the matrix and its location