If you do not have a WORKER window below *** open one now by invoking the 'Worker Window' *** option in the 'Coursework' menu.
You should already have met some of the features of the Fortran77 programming language in the Introductory Course. IF YOU HAVE NOT COMPLETED THE PROGRAMMING TUTORIAL IN THE INTRODUCTORY COURSE, YOU ARE STRONGLY ADVISED NOT TO PROCEED WITH THIS TUTORIAL, BUT TO GO BACK AND DO IT!
The Fortran language is still evolving; Fortran77 is an internationally agreed standard to which nearly all current compilers conform, but there is now a revised standard, Fortran90, which has been agreed but which has not yet been widely implemented. However, many compilers, including that available on this machine, already incorporate some of the new features of the Fortran90 standard as extensions to Fortran77. We will introduce some of these new features in this tutorial but will always point out that they are not part of the Fortran77 standard, but are extensions thereof by labelling them F90. However, YOU ARE STRONGLY ENCOURAGED TO USE THE F90 FEATURES.
We will begin by reminding you of the structure of the projectile program that featured in the Introductory Course but we will now try to be a little more systematic in our description! Get hold of a copy of the program by going to the WORKER window, clicking the mouse and typing
cp /usr/local/text/cplabwork/examples/fortprogs/proj1.f proj1.for
cp $TFILES/cplabwork/examples/fortprogs/proj1.f proj1.f
Then invoke the emacs editor on your copy of the file by typing
ue proj1.f
Click here if you wish to return to the Table of Contents.
One of the special purposes for which the first six columns may be used is shown in the projectile program: if the first column contains a 'c' or a '*' then the whole line is treated as a COMMENT and is ignored when the program is compiled into executable code.
A second special use of the first six columns is to specify a CONTINUATION LINE. If column 6 of a line contains any character other than a space or a zero then the line is treated as a continuation of the previous line. In this case columns 1-5 of the continuation line MUST BE BLANK, and column 7 is treated as if it came immediately after column 72 of the previous line!
The third special use of the first six columns (actually, the first five columns) is for identifying a statement by means of a STATEMENT LABEL, which is an integer, written in columns 1-5. The number chosen can be any integer in the range 1-99999 as long as it is unique to the statement being labelled. We will encounter uses of statement labels later in the tutorial; for now, note that they are not generally required and their use is DISCOURAGED.
!!!!!!!!!!!!!!!!!!!!!!!!!!!! F90 FEATURE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
The strict Fortran77 standard requires the use of upper-case letters only in program statements, except in comment statements or when writing strings of text to be used in printed output. Fortran90 allows the use of lower-case as well as upper-case letters. Note, however, that upper- and lower-case are EQUIVALENT; they are distinguished only when they form part of character sequences, NOT when used in names of variables or constants.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Click here if you wish to return to the Table of Contents.
The data items which appear in a Fortran77 program have a type associated with them. The allowed types are:
Real constants are numbers containing a decimal point and (optionally) preceded by a sign e.g.
4.7 -0.01 +3.14159 17. -.1
The exponent form represents real constants by a (signed) number (the mantissa), with or without a decimal point, followed by the letter e (or E) and a second number (the exponent), so the previous examples could be written:
47E-1 -1E-2 3.14159E0 0.17E2 -1E-1
Integer constants are numbers which do not contain any decimal point and which may, optionally, be preceded by a sign e.g.
4 -1 +275
Integers up to a certain size (dependent upon the particular computer) are stored with complete precision.
Character constants are sequences of characters, known as strings, enclosed in single quotes, or apostrophes, e.g.
'Computational Physics' 'a4' 'aaaa'
The apostrophes do not form part of the string and are not stored in memory, unless repeated e.g. 'I don''t' is a string containing a single apostrophe.
Fortran variables have names which denote storage locations in memory. The strict Fortran77 rules for names are that they
Particular implementations of Fortran may relax these rules e.g. in our example proj1.f, there is a variable called theta_rad which is clearly longer than 6 characters and includes the underscore character, but if you wish your code to be portable between different machines you should stick to the standard!
Variable names can be declared before the first executable statement of a program, e.g.
real x, height, range integer month, minute character*9 name, class, degree logical test double precision xplot, yplot
NOTE that in declaring a character variable, the length of the character string is specified by appending * followed by the number of characters in the string to the type. In the above example, name, class and degree are all declared to be character strings of length 9.
Fortran77 has some potentially dangerous rules about variable types. If a variable name is used without declaration, IT IS ASSUMED TO BE REAL if its name starts with a letter in the range a-h or o-z, whereas IT IS ASSUMED TO BE INTEGER if it starts in the range i-n.
Some programmers adopt the practice of always declaring all the variables used in a program, regardless of whether or not they conform to the implicit typing. Going back to proj1.f we see that x, y, u, vx, vy, g, dt, theta, theta_rad, and pi are all declared to be of type real, whereas nstep and max_steps are declared to be of type integer. In this case, the declarations conform to the implicit typing rules.
!!!!!!!!!!!!!!!!!!!!!!!!!!!! F90 FEATURE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
The statement
implicit none
at the start of a program overrides the implicit typing of Fortran77, requiring that all variables then be declared explicitly. Its use is widely regarded as good programming practice and you are STRONGLY ENCOURAGED TO USE IT.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Click here if you wish to return to the Table of Contents.
Remember that the assignment operator, =, has a different meaning to the usual arithmetic 'equals'. Thus
x = x+vx*dt
means 'evaluate the expression on the right hand side using the current values of the variables x, vx and dt, and then use it to overwrite the current value of x i.e. store the value of the expression in the memory location labelled by x'.
The arithmetic operators are
+ - / * **representing, respectively, addition, subtraction, division, multiplication and exponentiation. The first four appear explicitly in our example program, proj1.f.
It is important to be aware that there is an order of precedence for these operators which may matter when evaluating complicated expressions. The priority rule is: ** has highest priority followed by / and * followed by + and -
Within any one priority level, evaluation is carried out from left to right. For example in the expression
3.0+4.0**2.0-8.0/4.0+2.0exponentiation is performed first, causing the expression to reduce to
3.0+16.0-8.0/4.0+2.0followed by any multiplication or division, leading to
3.0+16.0-2.0+2.0which finally reduces to 19.0.
There is one important exception to the left -> right evaluation rule: multiple exponentiation. Thus for example
a**b**cis evaluated from right to left!
Ambiguities can always be resolved by the use of parentheses. Thus for example, in the expression
x+vx*dtthe multiplication of vx and dt is performed first, followed by the addition of the result to x. Had we wished first to add x to vx and then multiply by dt we could have written
(x+vx)*dtIn general, ANY EXPRESSION ENCLOSED IN PARENTHESES IS EVALUATED FIRST.
------------------------------------------------------------------- Exercise: what are the values of the following Fortran expressions? 5.+2.*3. (5.+2.)*3. 2.*3.**3. (2.*3.)**3. 2.**3.**2. -------------------------------------------------------------------In the evaluation of an arithmetic expression of the form
operand operator operandin Fortran77, one of the rules is that both operands must be of the same type (other than in expressions involving exponentiation of the form x**2). If one is an integer and the other is a real (a MIXED-MODE expression), then the integer will be converted to real before the operation is performed. The result is of the same type as the operands. MIXED-MODE assignment is also possible but should be used with care.
Examples:
9*tempc/5Here tempc is real by default, so 9 is converted to 9.0 and the multiplication is performed according to the rules of precedence discussed above. The result is of type real and thus the denominator is first converted to 5.0 before the division is carried out, the final result being of type real.
a = 7*8Both operands on the r.h.s. are of type integer, so the result of the multiply is 56, of type integer. This is then assigned to a, which is by default of type real, so a takes the value 56.0
j = 6.0*7.0/9.0Here the r.h.s. is a real expression which evaluates to 4.666... The value assigned to the integer j is then 4, the fractional part being discarded (this is known as truncation).
******************************* * Warning on integer division * *******************************Any fractional part remaining on integer division is also discarded, which can catch out the unwary programmer! For example,
i = 7 j = 2 k = i/jgives k = 3.
Similarly
i = 7 j = 2 a = i/jgives a = 3.0, from the rules for mixed-mode assignment.
Type conversion is possible using type conversion operators; thus applied to the previous example
i = 7 j = 2 a = real(i)/real(j)gives a = 3.5, which is probably what you intended!
It is also possible to convert from type real to type integer; int(a) yields an integer result, the integer part of a.
In proj1.f you see an example of a comparator, or relational operator, which is used in the line
do while(y.ge.0.0)to test whether or not y is greater than or equal to zero. The expression y.ge.0.0 is called a relational expression because it expresses a relation between two values. There are six relational operators in Fortran which may be used to construct relational expressions of type 'logical' which are either true or false - that is, they correspond in value to one of the two logical (or Boolean) constants .TRUE. or .FALSE.
The complete set of relational operators is as follows:
****************************** * Warning on comparing reals * ******************************It can be dangerous to use the relational operators .ne. and .eq. for comparing reals because of rounding errors. For example, in finite precision, 1./3. has the value 0.3333333, say, so that 3.0*(1.0/3.0) has the value 0.9999999 NOT 1.0, so that the comparison
3.0*(1.0/3.0).eq.1.0evaluates to .FALSE. instead of .TRUE.
Relational operators are used to create a logical expression, which takes the value .TRUE. or .FALSE.; logical expressions can be combined using logical operators to perform more sophisticated logical tests. The logical operators are
.AND. .OR. .EQV. .NEQV. .NOT.and their use is illustrated by the following table, where L1 and L2 are logical expressions;
L1 L2 L1.OR.L2 L1.AND.L2 L1.EQV.L2 L1.NEQV.L2 -------------------------------------------------------------------------- .TRUE. .TRUE. .TRUE. .TRUE. .TRUE. .FALSE. .TRUE. .FALSE. .TRUE. .FALSE. .FALSE. .TRUE. .FALSE. .TRUE. .TRUE. .FALSE. .FALSE. .TRUE. .FALSE. .FALSE. .FALSE. .FALSE. .TRUE. .FALSE. --------------------------------------------------------------------------Thus .OR. gives a result that is only true if either of its operands is true, whereas .AND. gives the result true only if both operands are true.
.EQV. gives a true result only if both L1 and L2 are logically the same value, whilst .NEQV. gives a true result if L1 and L2 have opposite values. They may be used to simplify more complex logical expressions; e.g. the following two expressions have the same value:
(a.lt.b.AND.x.lt.y).OR.(a.ge.b.AND.x.ge.y) a.lt.b.EQV.x.lt.yThe remaining operator, .NOT., takes only a single operand, whose value it inverts. For example, the following two expressions are equivalent:
.NOT.(a.lt.b.EQV.x.lt.y) a.lt.b.NEQV.x.lt.yPriority rules for logical operators apply just as they did for arithmetic operators:
Operator Priority ---------------------------------- .NOT. 1 (high) .AND. 2 .OR. 3 .EQV./.NEQV. 4 (low) ----------------------------------
As before, parentheses may be used to make the order of evaluation clear.
There is only one character operator, the concatenation operator //, which can be used to combine two strings to form a third string. For example:
'Wed'//'nesday' is equivalent to the string 'Wednesday'
Often we need to assign an initial value to some or all of the variables in a program. Fortran77 allows us to do this by means of the data statement, which takes the form:
data 'namelist1'/'clist1','namelist2'/'clist2',........or
data 'namelist1'/'clist1'/'namelist2'/'clist2'.........where 'namelist*' is a list of variables names and 'clist*' is a list of constant values, with the same number of items as the corresponding 'namelist'. The effect is to give each variable in 'namelist' the initial value specified by the corresponding item in 'clist'. The normal rules of arithmetic apply and the constant will be type-converted if necessary to match the type of the variable. Note: the quotation marks are not part of the sytax.
Example:
data a,b,n/1.0,2.0,3/,code/8667.0/gives the real variables a and b initial values of 1.0 and 2.0, the integer variable n an initial value of 3, and the real variable code an initial value of 8667.0.
Several items can be given the same initial value by preceding the constant by a repetition count e.g.
data i,j,k,l,m,n/6*0/A data statement must appear AFTER any specification statements. It is usual, but not necessary to put data statements at the beginning of the executable part of the program.
***************************** * Warning on initial values * *****************************Many computer systems initialise all variables to a pre-defined value, usually 0, but IT IS NEVER SAFE to assume that this is the case.
Although the data statement can be used to give a value to a variable that is never changed e.g.
data pi/3.14159/there is a preferred way of naming constants, which is to use the parameter statement. It takes the form
parameter ('name1'='const1', 'name2'='const2',......)with obvious meaning. Thus we could write
parameter (pi=3.14159)Then on every occasion that pi is referred to in the program, the value 3.14159 will be used.
Constant expressions can also be used e.g.
parameter (third=1.0/3.0, pi3by4=3.0*pi/4.0)Where an expression is used there are some restrictions:
Click here if you wish to return to the Table of Contents.
The repetition of a number of statements a predetermined number of times is so important that Fortran contains a special construct that allows this to be done. In general, a "do loop" may contain any Fortran statements, including another do statement, known as a "nested do loop".
!!!!!!!!!!!!!!!!!! F90 FEATURE: the 'end do' statement !!!!!!!!!!!!!!!!!!!!!!!!
Fortran90 denotes the terminating statement of a "do loop" by means of the end do statement.
The syntax is:
do index=int1,int2[,int3] 'statements' end do
where:
Note: The notation [,int3] simply means that int3 is optional; it is assumed to be 1 if omitted. The square brackets are not part of the syntax!
The number of times that the body of the "do loop", denoted by 'statements', is executed (known as the "trip count") is calculated from the formula:
MAX(0, INT((int2-int1+int3)/int3))where INT denotes the integer part of the ensuing expression. This number is calculated BEFORE the loop starts. If zero, it means that the body of the "do loop" is NOT executed.
Examples:
do i=0,100,5has a trip count of 21 whereas
do i=0,100,9has a trip count of 12
Example: a very simple program to compute the squares of the integers from 1 to 10, and print them out.
program squares c c a program to calculate the squares of the first ten integers c implicit none integer int,intsq do int = 1,10 intsq=int*int write(*,*) 'The square of ',int,' = ',intsq end do stop end
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!The Fortran77 syntax involves the use of a labelled statement to denote the end of the loop and is:
do m, index=int1,int2[,int3] 'statements' m continue
where:
Note: the comma after m in the do statement is optional - you may encounter both forms.
!!!!!!!!!!!!!!!!!!!! F90 FEATURE: the 'do while' construct !!!!!!!!!!!!!!!!!!!
There is an example of a "do while loop" in proj1.f. This construct permits the repeated execution of one or more Fortran statements conditional upon the status of a logical expression, rather than for a fixed number of repetitions. The syntax is:
do while ('logical expression') 'statements' end dowhich loops through 'statements' for as long as 'logical expression'evaluates to .TRUE.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
------------------------------------------------------------------------------ Exercise: Go to the WORKER WINDOW and use the editor to write a program to print out the factorial of n (an integer) from n=1 to 20. NOTE: the filename that you use for storing your program must have the default extension .f otherwise it will not be recognised by the compiler, so use something like ue fact.f Your program should not use more than one "do loop". Try compiling and running your program. What goes wrong if you use integer variables in your program ?? Remember, the command which invokes the compiler is f77 'filename' which produces an executable file called a.out or f77 -o 'file2' 'file1' if you want the executable to be called 'file2'. (Do not type the quote marks!). To run your program, simply type the name of the executable file. *** CHECKPOINT 1 *** ------------------------------------------------------------------------------
Click here if you wish to return to the Table of Contents.
There are two forms of the IF construct. The simple form (which is, strictly speaking, a hangover from earlier versions of Fortran) is:
if ('logical expression') 'statement'Here 'statement' is any executable statement and is only implemented if 'logical expression' has the value .TRUE.
Example:
if (volts.gt.threshold) signal=gain*input
There is also a block IF construct:
if ('logical expression 1') then 'statements1' else if ('logical expression 2') then 'statements2' else if ('logical expression 3') then 'statements3' else 'statements4' end ifHere 'statements*' are blocks of one or more lines of Fortran. Only one block gets executed in a particular run; e.g. 'logical expression 2' is only tested if 'logical expression 1' has the value .FALSE. and so on.
Any number, including zero, of else if blocks can be used and the final "catch-all" else block can be omitted. Thus the simplest form is
if ('logical expression 1') then 'statements1' end ifwhich is equivalent to the simple form described above in the case where 'statements1' consists of just a single statement.
Example: a program to compute the number of points with positive integer coordinates inside the ellipse x**2/16 + y**2/25 = 1
program ellipse c c declarations c implicit none integer npts,ix,iy c c initialise counter c npts = 0 c c loop over x direction c do ix = 1,4 c c loop over y direction c do iy = 1,5 c c test to see if point lies within ellipse c if(real(ix*ix)/16.0 + real(iy*iy)/25.0.lt.1.0) then npts = npts +1 end if end do end do write(*,*) 'Number of points: ',npts stop end
Note the use of the "program statement"; not essential, but good programming practice. The name of the program may be freely chosen, within the Fortran naming conventions.
Note that indentation has been used to clarify the loop structure, although not necessary ; the contents of each "do loop" are indented by two spaces with respect to the do and end do statements, as are the contents of the if block.
----------------------------------------------------------------------------- Exercise: go to the WORKER window and get a copy of the ellipse program by typing cp /usr/local/text/cplabwork/examples/fortprogs/ellipse.f ellipse.f Try compiling and running this program. Remember, the command which invokes the compiler is f77 'filename' which produces an executable file called a.out or f77 -o 'file2' 'file1' if you want the executable to be called 'file2'. (Do not type the quote marks!). To run your program, simply type the name of the executable file. ------------------------------------------------------------------------------
Example: a program to read positive integers and compute their average; negative integers are ignored whilst zero terminates the program.
program average c summary: program to read positive integers and find their average, c ignoring negative integers and terminating on zero c variable definitions: c numint number of integers read in so far c intsum running total of integer values c int current integer c n for do loop control c c declarations c implicit none integer numint,intsum,int,n c c initialise counter and total c numint = 0 intsum = 0 n = 1 do while (n.eq.1) c c input integer from keyboard c write(*,*) 'Input integer' read(*,*) int c c test for negative or zero values c if(int.gt.0) then numint = numint + 1 intsum = intsum + int else if(int.eq.0) then write(*,*) 'Number of positive integers: ',numint, & ' Average: ',real(intsum)/real(numint) stop end if end do end
Note the continuation line, denoted by '&' in column 6.
Note the difference between the stop statement, which signifies the logical end of the program and terminates execution, and the end statement, which denotes the physical end of the program. Any program that you write must have an end statement as its final statement, or it will not compile. It should also have a stop statement, although it may well compile and run without one.
------------------------------------------------- Exercise: Get a copy of the average program: cp /usr/local/text/cplabwork/examples/fortprogs/aver.f aver.f and try it out. ------------------------------------------------------
Click here if you wish to return to the Table of Contents.
It is often desirable to refer to a group of related items of the same type by giving them the same group name, and identifying the individual items by their positions within the set. Arrays are used for this purpose in Fortran.
Each item within an array is referred to as an array element and is identified by an integer index or subscript which follows the array name in parentheses. An array is always declared in an extended type declaration statement, which also declares the range of possible subscripts, and hence the size of the array. For example
integer n(100)reserves 100 integer locations in memory called n(1), n(2), n(3),.....n(100). In statements which reference an array element, the index or subscript may be any integer expression e.g. n(3*j+2).
Array elements may be used anywhere that a variable name can be used, but are especially useful in conjunction with a "do loop", whose index can be used as an array subscript, enabling each pass through the loop to use a different array element.
Example: here are the bare bones of a program to find the largest element of an array of ten integers. You are invited to complete it:
program largest c c variables: c c ivec array to hold numbers c large largest array element c j labels largest array element c i do loop index c c declarations c implicit none integer ivec(10),large,i,j c c input the array elements c write(*,*) 'Enter 10 integers, one per line:' read(*,*) (ivec(i), i = 1,10) c c start by assuming first element to be largest.... c large = ivec(1) j = 1 do i = 2, 10 c c now write the rest of this loop yourself........ c end do write(*,*) 'Element ',j,' is largest and has value ',large stop end
Note: in this example the use of a so-called "implied do loop" in the read statement which inputs the ten elements of the array ivec in sequence.
---------------------------------------------------------------------- Exercise: get the skeleton program cp /usr/local/text/cplabwork/examples/fortprogs/largest.f largest.f and try to complete it; check your program by compiling and running it. *** CHECKPOINT 2 *** -----------------------------------------------------------------------
By default, array subscripts in Fortran start at 1, but this can be overridden; for example
real v(-4:3)declares a real array with 8 elements v(-4), v(-3),.....v(3) The first example could equally well have been written
integer n(1:100)
There are many instances where it is useful to be able to declare an array with more than one subscript; for example, to store the values of the electrostatic potential at points in the x-y plane. Fortran77 allows us to have up to seven subscripts for a single array. The number of subscripts is referred to as the DIMENSION of the array.
Examples:
real potl(100,100) integer pressure(20,40,30)The first of these could equally well be written
real potl(1:100,1:100) or real potl(1:100,100) or real potl(100,1:100)
An element of a multi-dimensional array must always be referred to with the correct number of subscripts and can, of course, be used in exactly the same way as a variable or an element of a one-dimensional array.
Arrays may have characters rather than numbers as elements, for example, we might want to process a set of names of students by tutorial group and serial number within the group:
program namelist c c variable definitions: c c igroup labels a group c ident labels an individual c name stores names in required order c next next name in sequence c c one '*' terminates a group c two '**' terminates the whole data set c c declarations c implicit none character*15 name(30,10), next integer igroup,ident igroup = 1 10 ident = 1 20 read(5,*) next if(next.eq.'*') then igroup = igroup +1 go to 10 else if(next.ne.'**') then name(ident,igroup) = next ident = ident + 1 go to 20 end if c now process the data in the array name............
Note the use of the go to statement together with statement labels, to transfer program control conditionally. The use of the go to is STRONGLY DISCOURAGED as it makes program logic difficult to follow and can lead to poorly structured code.
--------------------------------------------------------------------------- Exercise: can you devise a way of aavoiding the use of "go to" statements and statement labels in the previous example, using the F90 constructs that you have already met? ---------------------------------------------------------------------------
We can use an implied do loop to input to or output from a part, or the whole of a multi-dimensional array e.g.
read(5,*) ((potl(i,j),i=2,25),j=10,50)
**************************** * Warning on storage order * ****************************
The elements of a one-dimensional array occupy consecutive storage locations in memory but it is not immediately obvious what happens with higher- dimensional arrays. In fact in Fortran, multi-dimensional arrays are stored in such a way that the first subscript changes most rapidly e.g. the elements of
integer mat(3,3)are stored with mat(1,1), mat(2,1), mat(3,1), mat(1,2),...... in consecutive locations in memory. This is important to know if you wish to optimise the speed of execution of a program that manipulates arrays. Thus in the example above on the use of implied do loops to read into a two-dimensional array it would be less efficient to write
read(5,*) ((potl(i,j),j=10,50),i=2,25)because the innermost loop is accessing elements which do not correspond to consecutive locations in memory.
Click here if you wish to return to the Table of Contents.
The simplest form of input and output, which utilises only the keyboard and screen of your terminal, is known as list-directed. You have already met examples in the program proj1.f. In fact that program did not make use of the very simplest forms which we now describe.
print*, 'expression list' or write(*,*) 'expression list' or write(6,*) 'expression list'In the third form, 6 denotes the default output device, the terminal screen, for historical reasons. It is better and safer to use the second form in which * denotes the default device.
The values of any literals, variables, constants or expressions in 'expression list' will be printed in the order in which they are listed. The form of numeric output is pre-determined by the compiler.
Examples:
print*, 'Distance versus velocity' print*, 'Slope = ', slope write(*,*) 'Specify launch speed u (m/sec) :'
read*, 'variable list' or read(*,*) 'variable list' or read(5,*) 'variable list'Here 5 denotes the default input device, the terminal keyboard, again for historical reasons. The second form is preferred.
Values are stored in the order in which the variables are listed. Data values must be separated by commas or blanks. As many lines as are needed will be read. Each read* statement will begin searching for values with a new line.
Examples:
read*, time read*, (x(j), j=1,100) read(*,*) theta
----------------------------------------------------------------------------- Exercise: Write a program to read in a and b, the sides of a rectangle, and print out the perimeter and area. *** CHECKPOINT 3 *** -----------------------------------------------------------------------------
We may wish to exercise more control over the appearance of our output than is afforded by the list-directed forms just described. Fortran makes provision for the use of 'format descriptors' to achieve user control over both input and output.
print k, 'expression list' or write(*,k) 'expression list' or write(6,k) 'expression list'
The values of any variables or expressions in 'expression list' will be printed in the order in which they are listed according to the specifications in a format statement with label k. We will discuss format in Section 8.
Examples:
print 100, alpha, beta print 50 write(*,99) x, (a(i), i=1,6)This last example again illustrates use of the implied do loop to print out elements of an array.
read k, 'expression list' or read(*,k) 'expression list' or read(5,k) 'expression list'The values of any variables or expressions in expression list will be input in the order in which they are listed according to the specifications in a format statement with label k. We will discuss format in Section 8.
Examples:
read 200, alpha, beta read(*,99) x, (a(i), i=1,6)
We may wish more generally to read from, or write to files rather than the standard input and output devices keyboard and screen. You may already have tried doing this in the Introductory Course Programming Exercises. The way in which this is done in Fortran77 is by means of the open statement, whose form is
open('olist')where 'olist' is a list of open specifiers chosen from the following set:
unit=u, file=fn, status=st, access=acc, form=fm, err=s, iostat=iosThe first of these, unit, MUST BE PRESENT, the others are all optional. The unit specifier takes the same form as in the read and write statements discussed above, and provided it is first in the list, the string unit= may be omitted, with only an integer value, u, specifying the unit number.
We shall not consider the full generality of the open statement here but restrict consideration to the following form:
open(unit=integer expression, file='filename', status='literal')designates the file named 'filename' for all input or output statements that refer to the unit number specified by the value of integer expression.
If the string 'literal' is 'old', the file must be an existing one; if 'literal' is 'new', the file must NOT be an existing one. If a file whose status is 'new' is successfully opened, its status is thereby changed to 'old' and any subsequent attempts to open the file as 'new' will fail.
'literal' may also be 'unknown', which is equivalent to omitting the status specifier and is implementation-dependent, or 'scratch' for a temporary file which is deleted when execution finishes.
Examples:
open(8, file='projdata') open(unit=15, file='data/run.1', status='old') open(unit=10, file='latest', status='new')
Each open statement should be matched by a corresponding close statement, once the unit in question is no longer needed by the program:
Examples:
close(8) close(unit=15) close(unit=10)
read(unit number,*,end=n) 'variable list'to read from the data file referenced by unit number, which must correspond to a unit number assigned to a file by a previous open statement, except for the case where unit number is 5, which is by default the terminal keyboard. * denotes list-directed input. end=n is optional and will cause control to pass to statement n if the read statement is executed after the last line of data has been read.
Examples:
read(15,*,end=200) x, y, z read(11,*) i, j, k, l
read(unit number, k, end=n) 'variable list'to read using the format statement labelled k. end=n is optional, as before.
Example:
read(15,99,end=200) u, v, w
write(unit number, *) 'variable list'to write data to a file specified by unit number , which must have been assigned in an open statement, except when unit number is 6 which is by default the terminal screen.
Example:
write(13,*) a, b, c
write(unit number, k) 'variable list'to write data to a file specified by unit number , which must have been assigned in an open statement, using the format statement labelled k.
Example:
write(8,100) a, (r(k), k=1,20)
Click here if you wish to return to the Table of Contents.
{{{OPTIONAL
This section should probably be regarded as optional if you are doing this tutorial for the first time. If you find it hard going, skip to section 9. The most readable way to specify the format in which data is to be input or output is by means of the "format" statement, referred to in the previous section. The general form of the format statement is:
k format('format descriptor')where 'format descriptor' is a character expression and k is a statement label. Format statements can appear anywhere in a program; a popular choice is to gather them all together just before the end statement.
Format is just about the hardest thing to get right in a Fortran program, so let us start with a simple example!
print 100, max, res 100 format(1x,i5,f9.3)The format descriptor consists of a list of format codes, with the following meanings:
Thus if, for example, max = 12345 and res = 12345.678 we would get the following output:
1234512345.678which is not very readable!
On the other hand, if say max = 1 and res = 2.0 we would get
1 2.000Your program may crash if you try to print too large a number for the field width; thus max = 876543 is too big for the format code i5.
Here is a table describing the effects of various format codes for output:
code meaning -------------------------------------------------------------------------- iw output an integer in the next w character positions fw.d output a real in the next w positions with d decimal places ew.d output a real in the next w characters using a scientific notation with d decimal places in the mantissa and four characters (including e and a possible sign) in the exponent dw.d as ew.d but for double precision numbers gw.d same as fw.d if there is room, otherwise ew.d nx ignore the next n character positions i.e. output n blanks an output character expression in a field of width w, truncating or padding with spaces as necessary; for truncation n leftmost characters are output; padding is on left a output character expression in a field of its own width tc output next item starting in character position c tln output next item starting n character positions before (tl) or trn after (tr) the current position 'abcd..' output the string of characters 'abcd..' starting at the next character position ---------------------------------------------------------------------------
You can use a repetition count for multiple instances of the same format code or codes in a format statement e.g.
10 format(1x,3i5,2(4x,a4))is equivalent to
10 format(1x,i5,i5,i5,4x,a4,4x,a4)
Separators in the list of format codes can be of two kinds:
Example:
print 100, max, res 100 format(1x,i5/f9.3)with max = 12345 and res = 12345.678 as in the first example, would produce
12345 12345.678What happens if there is a mis-match between the number of items in the output list and the number of format codes?
a) excess codes are ignored, for example,
print 100, jj 100 format('a=',i3,' b=',i3)if jj = 123 would produce
a=123 b=
b) if there are too few codes, a new line is taken, and the codes are repeated from the left parenthesis corresponding to the LAST BUT ONE right hand parenthesis! For example,
print 100, (a(i), i=1,80) 100 format(' Results:'/(1x,10f7.3))gives a header line followed by 8 lines of 10 items. However,
print 100, (a(i), i=1,80) 100 format(' Results:'/1x,10f7.3)would give 8 pairs of lines, each with Results: on the first line and 10 items on the next.
If the output from a Fortran program goes to a lineprinter, or to a file which then gets printed on a lineprinter, then the first character in each line is not printed, but is used for "carriage control" or as a "format effector".
The allowed format effectors are as follows:
character effect -------------------------------------------------------------------- space no extra action i.e. single spacing 0 skip an extra line i.e. double spacing 1 new page + overprint the last line (not always implemented) --------------------------------------------------------------------
As an example
100 format('1Results:'/(1x,10f7.3))starts printing on a new page.
Most of the output format codes described above are available as input format codes but are not widely used, as free-format (denoted by *) deals with most situations:
code meaning --------------------------------------------------------------------------- iw read the next w characters as an integer fw.d read the next w characters as a real with d decimal places if no decimal point is present; otherwise ignore d ew.d same as fw.d on input dw.d same as fw.d on input gw.d same as fw.d on input nx ignore the next n characters an read next n characters as characters; if n is less than length of input list item pad with blanks; in n is greater than length, store rightmost characters of input string in item a read sufficient characters to fill input list item tc next character to be read is at position c tln next character to be read is n characters before (tl) or trn after (tr) the current position ---------------------------------------------------------------------------
The treatment of reals by fw.d (or ew.d) perhaps needs an example to clarify;
read 100, a,b,c,d 100 format(f3.1,f2.2,f3.2,f1.0)then the result for two different examples is as follows:
data a b c d ------------------------------------------------- 123456789 12.3 .45 6.78 9. .23.56.8 0.23 0.5 6.8 -------------------------------------------------
}}}
Click here if you wish to return to the Table of Contents.
Subprograms, or procedures, are the basic building blocks of good Fortran programs (in the jargon, WELL-STRUCTURED PROGRAMS). There are two types of procedure or subprogram: subroutines and functions. A complete Fortran program consists of a main program and any number of subprogram program units.
Fortran contains a library of intrinsic functions providing the commonly used mathematical functions such as the trigonometric functions, which you have already met in the example program proj1.f. You can also write your own functions to supplement or replace those provided as part of the language. The key feature of a function subprogram is that it returns a result through its name, whereas subroutine subprograms do not. Generally a function takes one or more arguments and returns a result.
Here is an example of an intrinsic function, the square root, being used to calculate the area of a triangle of sides a,b,c from the formula
area = square root{s(s-a)(s-b)(s-c)}where 2s is the sum of the lengths of the sides:
program triangle c variable definitions: c a,b,c sides of triangle c s (a+b+c)/2 c area area of triangle c c declarations c implicit none real a,b,c,s,area c c read the lengths of the sides of the triangle c write(*,*) 'Input sides a,b,c :' read(*,*) a,b,c c c compute area using intrinsic function sqrt c s = 0.5*(a + b + c) area = sqrt(s*(s-a)*(s-b)*(s-c)) write(*,100) area 100 format(1x,'Area of triangle is: ',f10.4) stop end ----------------------------------------------------------------------------- Exercise: try modifying the triangle program to check that the input values of a,b and c do indeed correspond to a valid triangle, that is, they are all non-negative and the sum of any two is greater than the third. As usual you can get a copy by means of the command cp /usr/local/text/cplabwork/examples/fortprogs/triangle.f triangle.f *** CHECKPOINT 4 *** -----------------------------------------------------------------------------
Function subprograms are also known as external functions to distinguish them from intrinsic functions. Here is a simple example, a function to calculate the average of five numbers:
program mean c use a function subprogram to calculate the mean of a set of five numbers c c declarations c implicit none real a1,a2,a3,a4,a5,av,avrage c c input five real numbers c write(*,*) 'Input five real numbers :' read(*,*) a1,a2,a3,a4,a5 c c instance of function c av = avrage(a1,a2,a3,a4,a5) write(*,100) av 100 format(' Average of five numbers is :',1x,f10.4) stop end c end of main program c definition of function subprogram real function avrage(x1,x2,x3,x4,x5) c this function returns the average of its five arguments c c declarations c implicit none real x1,x2,x3,x4,x5,sum sum = x1 + x2 + x3 + x4 + x5 avrage = sum/5.0 return end
Notes:
'type' function 'name'('d1,'d2',.....)where 'type' is optional; if omitted the type is determined by the usual Fortran rules for 'name'. 'd1','d2' etc are dummy arguments that represent the actual arguments that will be used when the function is used (in the jargon, referenced).
result = fun()
A subroutine subprogram has the same overall structure as a function subprogram except that the first statement is a subroutine statement rather than a function statement. The chief difference lies in how they are referenced and how their results are returned.
As we have just seen, a function is referenced by writing its name, followed by any arguments enclosed in parentheses. Control is then transferred from the current statement to the statements contained within the function. The execution of the function uses the actual values provided for its arguments, substituting them for the dummy arguments in the function definition, and calculates a value, the function value, which is then available as the value of the function reference in the main program.
A subroutine, on the other hand, is accessed by means of a call statement, which gives the name of the subroutine and a list of arguments which are used to transfer information between the main program and the subroutine:
call 'name'('arg1,'arg2',..............)The call statement transfers control to the subprogram, whose statements are executed until a return statement is encountered, when control returns to the statement immediately following the subroutine call.
As a simple example, let us rework the previous example to use a subroutine instead of a function subprogram:
program mean c use a subroutine subprogram to calculate the mean of a set c of five numbers c c declarations c implicit none real a1,a2,a3,a4,a5,av c c input five real numbers c write(*,*) 'Input five real numbers :' read(*,*) a1,a2,a3,a4,a5 c c subroutine call c call avrage(a1,a2,a3,a4,a5,av) write(*,100) av 100 format(' Average of five numbers is :',1x,f10.4) stop end c c end of main program c c definition of subroutine subprogram c subroutine avrage(x1,x2,x3,x4,x5,xbar) c this subroutine returns the average of its first five arguments c in the sixth argument c c declarations c implicit none real x1,x2,x3,x4,x5,sum,xbar sum = x1 + x2 + x3 + x4 + x5 xbar = sum/5.0 return end
Notes:
Note that it is possible to have array names as subroutine arguments; the array or arrays must be declared within the body of the subroutine as well as in the calling routine. However, unlike in a main program, where the dimensions of an array must be declared of fixed size, an array declaration within a subroutine may specify the name of a variable in the declaration.
For example, here is a fragment of a program which calls a subroutine to take a vector of 'number' data events (up to a maximum of 150) and return a character array of size 70 x 'number' which can then be printed to give a crude histogram
program analys implicit none integer number real events(150),xmin,xmax character*1 matrix(70,150) : : call hist(xmin, xmax, events, matrix, number) : : stop end subroutine hist(xlow, xhigh, dvec, harray, n) implicit none integer n real dvec(n),xlow,xhigh character*1 harray(70,n) : : return end
Click here if you wish to return to the Table of Contents.
{{{OPTIONAL
Subprograms are useful in structuring large programs into subtasks, but communication between the different program modules via parameter lists is not always appropriate. There may be a body of variables which have to be accessed by many of the subtasks but don't really 'belong' to any of them. Fortran allows us to declare a "common" block of variables for this purpose.
A named block of storage is defined by the statement:
common/'name'/'n1','n2',....where 'name' is the global name of the "common" block and 'n1', 'n2',... is a list of local variable names, array names or array declarators. For example,
integer age(50),num real mark(50,6),av,avrage common/exam/num,mark,av(50),age,avragedefines a "common" block called exam which consists of 402 numeric storage items. The first of these is an integer, num, the next 300 a two-dimensional array mark, the next 50 a real array av, the next 50 an integer array age and the last a real variable avrage.
********************************* * Warning on common block names * *********************************Because the name of a "common" block is global, it must be different from the names of any other "common" blocks or program units.
Notes:
common/exam/n,total(50,6),av(50),nyrs(50),avyrsor even as
common/exam/n,score(50,7),nage(50),avragewhere the two real arrays have been declared as a single real array. Because of the rule about storage order in Fortran77, those elements of score with second subscript 7 occupy the last 50 storage locations and thus correspond exactly to the array av in the first specification.
As well as blocks of storage of fixed size with global names, Fortran77 allows us to have a single further block of storage that is available to any program unit and that has neither a name or a fixed size. This is known as "blank common" and is declared thus:
common 'n1','n2',.....where 'n1', 'n2',... is a list of local variable names, array names or array declarators. For example,
common x,y,a(-10:10)
Notes:
}}}
Click here if you wish to return to the Table of Contents.