# Subroutines and Functions

### This worksheet is also available in PDF format.

This worksheet makes use of several examples programs that are all available for download from this website.

## Aims

By the end of this worksheet you will be able to:

- Understand the use of subroutines and functions to make your code more efficient and easier to read.

## Re-using code – the subroutine

Examine the following program

program output implicit none real,dimension(3) :: a,b,c character :: answer*1 !initialise arrays a = 1.5 b = 2.5 c = 3.5 write(*,1) 'a',aprint *, 'type y to continue or any other key to finish'read *, answerif (answer /= 'y') stopwrite(*,1) 'b',bprint *, 'type y to continue or any other key to finish'read *, answerif (answer /= 'y') stopwrite(*,1) 'c',cprint *, 'type y to continue or any other key to finish'read *, answerif (answer /= 'y') stopwrite(*,1) 'a*b*c',a * b * c 1 format(a,3f8.3) end program output

The program sets up some arrays and then outputs them. At three stages in the program (bolded), it asks whether it should continue; it stops if the answer is not 'y'. Notice that the three bolded parts of the code are *identical. *

Simple enough – but look at the amount of code! Most of it is the same – wouldn't it be nice to re-use the code and cut down on the typing? The answer is to use **subroutines**.

program output1 implicit none real,dimension(3) :: a,b,c !initialise arrays a = 1.5 b = 2.5 c = 3.5 write(*,1) 'a',acall prompt()write(*,1) 'b',bcall prompt()write(*,1) 'c',ccall prompt()write(*,1) 'a*b*c',a * b * c 1 format(a,3f8.3) end program output1 !++++++++++++++++++++++++++++++++++++++++++++++subroutine prompt()!prompts for a keypressimplicit nonecharacter answer*1print *, 'type y to continue or any other key to finish'read *, answerif (answer /= 'y') stopend subroutine prompt

Examine the code, each time we use type

call prompt()

the program jumps to the line

subroutine prompt()

then executes each line of the code it finds in the subroutine until it reaches the line

end subroutine prompt

and then returns to the main program and carries on where it left off.

The program is much easier to understand now. All the code for prompting is in one place. If we ever need to change the code which prompts the user to continue, we will only ever need to change it once. This makes the program more **maintainable****.**

## Arguments to subroutines

We have seen that subroutines are very useful where we need to execute the same bit of code repeatedly.

The subroutine can be thought of as a separate program which we can call on whenever we wish to do a specific task. It is independent of the main program – it knows nothing about the variables used in the main program. Also, the main program knows nothing about the variables used in the subroutine. This can be useful – we can write a subroutine using any variable names we wish and we know that they will not interfere with anything we have already set up in the main program.

This immediately poses a problem – what if we **want **the subroutine to do calculations for us that we can use in the main program? The following program uses **arguments** to do just that.

Example: a program that calculates the difference in volume between 2 spheres.

program vols !Calculates difference in volume of 2 spheres implicit none real :: rad1,rad2,vol1,vol2 character :: response do print *, 'Please enter the two radii' read *, rad1,rad2call volume(rad1,vol1)call volume(rad2,vol2)write(*,10) 'The difference in volumes is, ',abs(vol1-vol2) 10 format(a,2f10.3) print *, 'Any more? - hit Y for yes, otherwise hit any key' read *, response if (response /= 'Y' .and. response /= 'y') stop end do end program vols !________________________________________________subroutine volume(rad,vol)implicit none real :: rad,vol,pi !calculates the volume of a sphere pi=4.0*atan(1.0) vol=4./3.*pi*rad*rad*rad !It's a little quicker in processing to do r*r*r than r**3! end subroutine volume

When the program reaches the lines

call volume(rad1,vol1)

It jumps to the line

subroutine volume(rad,vol)

The values, **rad1** and **vol1 **are passed to the subroutine. The subroutine calculates a value for the volume and when the line :

end subroutine volume

is reached, the value of the volume is returned to the main program

**Points to notice – these are very important – please read carefully**

- You may have several subroutines in your program. Ideally, a subroutine should do a specific task – reflected by its name.
- All the variables in subroutines, apart from the ones passed as arguments, are 'hidden' from the main program. That means that you can use the same names in your subroutine as in the main program and the values stored in each will be unaffected – unless the variable is passed as an argument to the subroutine.
- It is very easy to forget to declare variables in subroutines. Always use
**implicit none**in your subroutines to guard against this. - All the variables in the subroutine
**must**be declared. - The positioning of the arguments (in this case, rad and vol) is
**important**. The subroutine has no knowledge of what the variables are called in the main program. It is**vital**that the arguments agree both in**position**and**type**. So, if an argument to the subroutine is**real**in the main program, it must also be**real**in the subroutine. - If an argument to the subroutine is an array, it must also be declared as an array in the subroutine.

##### Exercise 6.1

Write a program that calculates the difference in area between two triangles. Your program should prompt the user for the information it needs to do the calculation. Use a subroutine to calculate the actual area. Pass information to the subroutine using arguments.

## User Defined Functions

We have already met FORTRAN **intrinsic functions **like **abs, cos, sqrt**. We can also define our own functions – they work in a similar way to **subroutines**.

As an example, let's write a program (**func.f95**) that does some trigonometry. As you know, the trig routines in FORTRAN use radians, not degrees - so it would be nice to write a function that does all the conversion for us.

print *,'Enter a number' read *, a pi=4.0*atan(1.0) print *,'the sine of ',a,' is ',sin(a*pi/180)

In this snippet, we are having to code the conversion from degrees to radians directly into the main part of the program. That's OK for a 'one-off', but what if we needed to do the conversion several times. Now look at this:

program func !demonstrates use of user defined functions implicit none integer, parameter :: ikind=selected_real_kind(p=15) real (kind=ikind):: deg,radsprint *, 'Enter an angle in degrees' read *, deg write(*,10) 'sin = ',sin(rads(deg)) write(*,10) 'tan = ',tan(rads(deg)) write(*,10) 'cos = ',cos(rads(deg)) 10 format(a,f10.8) end program func !_____________________________________________function rads(degrees) implicit none integer, parameter :: ikind=selected_real_kind(p=15) ! returns radians real (kind=ikind) :: pi,degrees,radspi=4.0_ikind*atan(1.0_ikind)rads=(degrees*pi/180.0_ikind) end function rads

What we have done, in effect, is to create our own function **rads**, which is used in an identical way to the intrinsic ones you have used already like **sqrt**, **cos**, and **abs**.

When the line

write(*,10) 'sin = ',sin(rads(deg))

is reached, the program jumps to

functionrads(degrees)

the value, **degrees**, is passed to the function. The function does some computation, then finally returns the calculated value to the main program with the line

rads=(degrees*pi/180.0_ikind)

*assigns*the value to its own name

*rads*.

- The function
**rads**converts the value of the argument, degrees, to radians. - Notice that we must declare the data type of the function both in the main program, and in the function itself
**as if it were a variable**. - Functions return
**one**value. This value, when calculated, is assigned to the name of the function as if it were a variable –

rads=(degrees*pi/180.0_ikind)

##### Exercise 6.2

Write a program that includes a function called

**real function average(n,list)**

where **n** is integer and is the number of items in the **list**, and **list **is a **real array**.

Write suitable code for reading the numbers from a file (or keyboard), and output the average of the numbers.

##### Exercise 6.3

Write a program that allows a user to enter the size of a square matrix. In the program write a subroutine to compute a **finite difference**** matrix**. Ensure your output is neatly formatted in rows and columns.

So, for a 10 by 10 matrix, we expect output to look like this

2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2 -1 0 0 0 0 0 0 0 0 -1 2

Check your attempt with finite.diffs.f95 on the website.