FORTRAN Lesson 2 Reese Haywood Ayan Paul In the previous lesson we learned how to compile and link the simple Fortran programs HelloWorld.f and MyNameIs.f using the g77 compiler. We also wrote a small program to take the average of a set of data, Average.f. In this lesson we will learn about the genral structure of algorithms, especially, the stucture required by Fortran, and some syntax, programming style, etc. by analyzing and modifying the Average.f program. 1 Understanding Fortran Syntax First we will tackle the unusual syntax needed by Fortran. I will try to stick strictly to the Fortran 77 standard. This will enable all the programs we write to be portable on different computers and even operating systems. Since a space shows up blank I will replace the blank with a subscript b. Thus, Program comput becomes bbbbbb Program comput. That said, every Fortran statement, or each step in the procedure, must be in columns 1–72. Columns 1–5 are reserved for statement numbers or labels. Column 6 is reserved for a continuation character. Columns 7–72 are reserved for the actual Fortran statement. One exception is comment statements. To make a comment, a ‘*’ or ‘C’ in the first column makes the compiler skip this line because it is a comment. An example will be helpful. Below we examine the FORMAT statement from the Average.f program in the last lesson. With a comment statement. 1 bbbb 5b FORMATb (1X,’THEb AVERAGEb ISb ’,F5.2) C The above line the format for output There are 4 spaces then the label, the number 5, which happens to be in column 5. Column 6 is empty because we are not continuing from the line above. The beginning of the Fortran statement is in column 7 and continues to column 40. The next line is a comment and ignored by the compiler. We could have written this statement as bb 5bbb FORMAT(1X,’THEb AVERAGEb ISb ’,F5.2) where the label is now in column 3, and we have removed the space between the word FORMAT and (1X. We have also removed the comment. Both statements are equivalent though some would prefer the first statement on aesthetic grounds. Since we have 5 columns to make a label we could have 99999 labels. As a personal preference I usually skip the first column and save it for comments. This would leave me with 9999 labels. 1.1 An Ideal program Below is the ideal program bbbbbb PROGRAM progname Nonexecutable statements bbbbbb bbbbbb Executable statements bbbbbb END The above program lays out the basic structure of a Fortran program. The first statement in the program is the Fortran command PROGRAM. progname is the name of the program. Once you name the program the name becomes a reserved word. If we named the program, comput, then comput cannot be used later in the program as a variable. Next is the body of the program, first non executable statements, which include delclaration of variables and parameters and assignment of initial values, and then executable statements. Finally, the Fortran END command. The PROGRAM statement is not needed by the compiler but it is a good idea to use it. Giving the program a good name will help us remember what the program does, without reading through all of the code. Technically, the name of the program, and also the name of any variables, should be less than 6 characters. Some 2 Fortran compilers will allow longer names, but using long names will limit the portablilty of your program. When naming your program or variables, not only should you limit the length of the variable to 6 characters, but the characters you use must be either letters or numbers; the first character must be a letter. Thus, comput, AVERG, rngk4, and deriv2 are all valid names, while 2deriv, W AVER, DISTANCE, etc. are not. Note that Fortran is not case sensitive. Thus, AVERG and averg are the same thing to Fortran. I will try to use ALLCAPS for Fortran commands, and lowercase for variables throughout our programs. 1.2 NonExecutable Statements Non executable statements are just what the name implies. The statements are not executed but are need by the compiler to define parameters, variables, etc. We could have called this the definitions statements or declarations. To define variables we have to know how Fortran interprets numbers. 1.2.1 Data Types There are six different data types in Fortran 77. Fortran 90 and newer allows you to define your own data types, but these are usually enough. The six types are: 1. INTEGER i.e. 32, -7 2. REAL i.e. -15.45, 3.14159 3. DOUBLE PRECISION i.e. 3.1415926536, 1.000000006 4. COMPLEX i.e. 1 − 2i, 5i 5. CHARACTER i.e. ’velocity’, ’Report 3’ 6. LOGICAL i.e. .TRUE., .FALSE. For this class we will deal mainly with the first two types, INTEGER and REAL. To define a variable that will hold the number of counts, an integer, and two variables that will hold the x and y position of a point, real values, we would add the following line to our program: 3 ... bbbbbb INTEGER counts bbbbbb REAL x,y ... To add more variables we just separate the names with a comma, as in the REAL statement above. Another command related to data types is the PARAMETER command. As the name says we define a parameter with the command. For example, if counts was the number of times to go through a loop, then we can define counts as follows: ... bbbbbb INTEGER counts bbbbbb REAL x,y PARAMETER bbbbbb b (counts=100) ... Defining parameter makes debugging, or changing values very easy. Say we want to calculated the area of a circle using area=3.141*rad**2. Then to change the value 3.141 we have to search through the code to find where we defined it, then update the value to be 3.14159, if we wanted it more accurate. If we had defined pi, as a parameter, we could just change it at the top of the program, then at every instance where we used pi, the value changes automatically. It is a good idea to define all of your variables explicitly in the INTEGER, REAL, etc. statements. However, you can define them implicitly. That is, if you name a variable beginning with the letters A-H or O-Z and did not include them in the data type definitions, the Fortran compiler will define them as REAL by default. If the variable name begins with I-N the compiler will define them as INTEGER by default. Sometimes this is okay, at other times you will wish you had. 1.3 Fortran Arithmetic There are five different operations that can be carried out in Fortran, shown below with the proper Fortran syntax. 1. Addition i.e. a+b 2. Subtraction i.e. a-b 4 3. Multiplication i.e. a*b 4. Division i.e. a/b 5. Exponentiation i.e. a**b In Fortran, the arithmetic carried out by the CPU is specified in the data type definition statements. This gives us 6 different types of data arithmetic, INTEGER, REAL, DOUBLE PRECISION, etc. Each type is different and will result in a different answer. Some examples will be helpful. 1.3.1 INTEGER Arithmetic Adding two plus two we get, 2+2 = 4. Dividing two by three we get, 2/3 = 0 The answer is zero because the integer 2 divided by the integer 3 is 0.66666... which is not an integer, so the answer is truncated. Truncation is different from rounding because if the program had rounded the answer would be 1. Truncation just gives the integer part of the computer answer, 0. We have to watch for this throughout our programs, otherwise when we are expecting a REAL number we may end up with the truncated part of it. 1.3.2 REAL Arithmetic Adding two plus two we get, 2.0+2.0 = 4.0. The difference in syntax is the decimal after the number. The decimal signifies REAL numbers are being used, not integer. Dividing two by three we have, 2.0/3.0 = 0.666666687. Wait you say, the answer is 0.666... . Why did we get the 87 at the end? This is known as a floating point error, which comes because the CPU cannot do infinite precision calculations. We will have to watch for this type of error in our programs. The problem is that REAL data types are only calculated to the 8th decimal place. Depending on the computer and compiler you are using, data values in the 8th decimal and beyond are not trustworthy. That is where DOUBLE PRECISION comes in, which gets us to the 16th decimal place. If we have a 64bit CPU we can even do quadruple precision which would get us to 32 decimal places. 2 Average.f We now return to the Average.f program, reprinted below. 5 ********************************************************** bbbbbb PROGRAM comput * * This program computes and prints the average * of a set of experimental data values. * bbbbbb INTEGER count bbbbbb REAL sum, x, averg * bbbbbb sum = 0.0 bbbbbb count = 0 * bbbbbb READ*, x bbbb 1b IF (x.NE.0.0) THEN bbbbbbbbbb sum = sum + x bbbbbbbbbb count = count +1 bbbbbbbbbb READ*,x bbbbbbbbbb GO TO 1 bbbbbb END IF * bbbbbb averg = sum/REAL(count) * bbbbbb PRINT 5, averg bbbb 5b FORMAT (1X,’THE AVERAGE IS ’,F5.2) * bbbbbb END ******************************************************* We can see immediately the program has the structure we mentioned in section (1.1) above. First we have the PROGRAM and END statements which signify the start and the end of the program respectively. Then we have the non executable statements defining the variables. Finally the executable statements that read in the values and print the average, finishing the program. Before we examine the body of the program we must learn a bit about procedural and functional programming. 6 3 Procedural vs. Functional Programming To understand how Fortran programs work we need to distinguish between Procedural and Functional programming, a distinction which is not always easy to see. Anyone that has used Mathematica has done functional programming. For example, in Mathematica, if we define the function recip[x_]:= 1/(1+x) we can iterate, or apply it multiple times, by using the built in Mathematica function, Nest[ ]. Thus, Nest[recip,x,3] would give a new function 1 1+ 1 1 1+ 1+x This is functional programming, functions are used to do calculations. In procedural programming, as the name suggests, procedures are used to do calculations. In Fortran, the same output would require at least four steps in the procedure, as shown below: ... x=number answ=1/(1+x) answ=1/(1+answ) answ=1/(1+answ) ... This example is not meant to say, use Functional programming because it is more compact, which is sometimes true, but rather to say, in procedural programming one has to do calculations step by step. We could have written the above program in two steps: ... x=number answ=1/(1+(1/(1+(1/(1+x))))) ... but this can become cumbersome very quickly, not to mention we have to be sure all of the parentheses match, (Do they?). Also, notice in the first program how answ is used in the third line. It is on the left and right hand side of the equal sign. This highlights another aspect of procedural 7 programming, once a variable is defined it can be used again anywhere in the program. I will illustrate this with a few examples. What will the value of answ be at the end of each program? Program 1: ... x=10 answ=x*2 answ=answ+x ... Program 2: ... x=3.14159 rad1=10 rad2=12 answ=2*x*rad1 circ1=answ answ=2*x*rad2 circ2=answ ... Program 3: ... a=5. b=6. answ=a**2+b**2 answ=sqrt(answ) answ=a ... The final value of answ in each case is 30, 75.39816, and 5. In Program 1, we first defined answ to be x times 2 which is 20. Then we added the current value of answ, 20, to x, 10, which gave us 30. In Program 2, we first defined answ to be the circumference of a circle with radius equal to rad1. Next we defined answ to be the circumference of a circle with radius rad2. So the final value of answ is 2 times 3.14159 times 12, which is 75.39816. In the final program we first calculate answ to be a squared plus b squared. 8 Next we take the square root of answ, which would be analogous to finding the hypotenuse of a right triangle. Unfortunately we lose the value of the hypotenuse and reset answ to a. So the final value is answ = 5. In Program 3, it would be easy to find the error if the value you wanted to calculate was the hypotenuse. However, if your code is 500, or even 5000, lines long, then it may not be so easy to find the mistake, lines 4 through 7 could contain the code to calculate the hypotenuse, but maybe line 357 is where answ is redefined as a. I give you this example as a warning. Once I spent a couple of days debugging a program because I had used a 0, (the number zero), in the place of an O, (the capital letter o). So when I tried to print the final value of C18O, I would get an error message that this value was not defined. How can we prevent this kind and other kinds of mistakes? Unless we all become perfect we cannot. Everyone makes a typo here and there. What we can do is make our programs simple, easy to read, and structured. Below we develop a problem solving strategy and code writing strategy that will make programming and debugging much easier. 4 Problem Solving There is a five step guide which we will follow in this class for writing code. They are: 1. State the problem clearly. 2. Describe the input and output information. 3. Work the problem by hand ( or with a calculator) for a simple set of data. 4. Develop a solution that is general in nature. 5. Test the solution with a variety of data sets. If we follow these steps we will ensure we have written a good program. Let’s return to the Average.f program and examine it in light of the steps mentioned above. 9 4.1 State the problem clearly Step 1 is usually an easy part of the problem as long as we are clear and and concise. In the case of taking the average of a set of data, stating the problem is rather simple. “We would like the average of a set of data.” 4.2 Describe the input and output information Step 2 is also simple to state, but not always simple to execute. To take the average of a set of data we need the data set read in and the average printed out. Therefore: INPUT– the list of experimental data OUTPUT– the average of the data 4.3 Work the problem by hand This step is the easiest to say, but not the always the easiest to do. Calculating the average of a set of numbers is simple on a calculator, but what about doing a linear least squares fit to a curved data set? Not as easy to do it by hand as it is to say it. 4.4 Develop a general solution Developing the solution is by far the hardest part. Although, if we follow the outline below we will be able to tackle most problems effectively. 4.4.1 Decomposition Break the problem into multiple steps. to take the average of a set of data we need to: • Read the data values and sum them. • Divide the sum by the number of data values. • Print the average. 10 4.4.2 Refine the decomposition To refine the decomposition we use pseudocode. Pseudocode is basically the code written in English instead of arithmetic i.e. the sum of one and two is three; compare to 1+2=3. For our average program we would have pseudocode that looks similar to the following: 1. Set the sum of the values to zero (or initialize the sum to zero). 2. Set a count of the values to zero. 3. As long as there are more data values, add the next data value to the sum. Add 1 to the count. 4. Divide the sum by the count to get the average. 5. Print the average. As a comparison the Fortran code corresponding to the pseudocode is below. 1. sum=0.0 2. count=0 3. IF(x.NE.0.0) THEN sum=sum+x count=count+1 ... END IF 4. averg=sum/REAL(counts) 5. PRINT 5, averg 4.5 Test the program The final step is to check the program so we know the output is correct. For example, if we had not converted counts to REAL in step 4 above, would the answer be different? Is the average of 10.5, 11.0 and 11.5 equal to 11.0? etc. Testing is the crucial step. Maybe we made a typo somewhere in the program. We will not know for sure unless we have tested the problem. 11 4.6 Your next task 1. q Given the sides of a triangle, a,b,c, write a program to find its area. (Area = s(s − a)(s − b)(s − c) whare 2s = a + b + c). 2. Write a program to reac the radius of a circle and compute its circumference and area. 3. Write a program to express a quantity in millimeters, in meters centimeters and millimeters. (observe what you get if you put decimals in you initial value in mm) 4. Given the x, y coordinates of a point, write a program to compute its r, √ 2 2 θ coordinates. (r = x + y , θ = tan−1 ( xy )). 5. Write a program that computes the third side of a right triangle, given the value of the first two sides. The final program should print the length of each side and the angles at each vertex. Use the problem solving technique above and follow the syntax presented in the beginning of the handout. See the next section for some needed Fortran commands and information. 5 5.1 Some useful Fortran commands Data handling INTEGER var1,var2,var3 (defines integer variables) REAL var1,var2,var3 (defines real variables) DOUBLE PRECISION var1,var2,var3 (define double precision variables) PARAMETER (name1=expression, name2=expression, ...) (i.e. pi=3.14159) CHARACTER*LEN char1,char2,char3 (define a character, LEN defines the length of the character) 5.2 Data Input/Output We will learn about the details of the syntax of PRINT and READ later PRINT *, expression list READ *, variable list 5.3 Arithmetic Priorities of Arithmetic Operations 12 1. Parentheses 2. Exponentiation 3. Multiplication and Division 4. Addition and Subtraction A+B (add A to B) A-B (Subtract B from A) A*B (Multiply A with B) A/B (Divide A by B) A**B (Raise A to the power B, i.e. 2**3=8) 5.4 Some built in functions SQRT(x) (Square root of x) ABS(x) (Absolute value of x) SIN(x) (Sine of angle x, x in radians) COS(x) (Cosine of angle x, x in radians) ASIN(x) (sin−1 of x) ACOS(x) (cos−1 of x) ATAN(x) (tan−1 of x) EXP(x) (e raised to the power x) LOG(x) (Natural log of x) LOG10(x) (Log base 10 of x) INT(x) (Convert real value to integer value) REAL(i) (Convert integer value to real value) MOD(i,j) (Integer remainder of i/j) 13
© Copyright 2026 Paperzz