Professional Documents
Culture Documents
Fortran 90 Tutorial
Dr. C.-K. Shene Associate Professor Department of Computer Science Michigan Technological University
1997 C.-K. Shene
since July 1, 1998. You are visitor Last update: August 20, 1998.
Select the topics you wish to review: Introduction and Basic Fortran Selective Execution (IF-THEN-ELSE and SELECT CASE) Repetitive Execution (DO Loops) Functions and Modules Subroutines One-Dimensional Arrays Multi-Dimensional Arrays Formated Input and Output
Please send comments and suggestions to shene@mtu.edu
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/fortran.html8/5/2006 8:01:06 PM
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/intro.html8/5/2006 8:01:34 PM
Program structure
Program Structure
Your program should have the following form: PROGRAM program-name IMPLICIT NONE [specification part] [execution part] [subprogram part] END PROGRAM program-name
Contents in [ ] are optional. Keyword IMPLICIT NONE must present. A program starts with the keyword PROGRAM, r followed by a program name, r followed by the IMPLICIT NONE statement, r followed my some specification statements, r followed by the execution part, r followed by a set of internal subprograms, r followed by the keywords END PROGRAM and the program name. For improving readability, your program should add comment lines.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap01/struct.html8/5/2006 8:01:48 PM
Fortran identifiers
Fortran Identifiers
A Fortran identifier must satisfy the following rules:
q q q q q
It has no more than 31 characters The first character must be a letter, The remaining characters, if any, may be letters, digits, or underscores, Fortran identifiers are case insensitive. That is, Smith, smith, sMiTh, SMiTH, smitH are all identical identifiers. Correct Examples: r MTU, MI, John, Count r I, X r I1025, a1b2C3, X9900g r R2_D2, R2D2_, A__ Incorrect Examples: r M.T.U.: only letters, digits, and underscores can be used r R2-D2: same as above r 6feet: the first character must be a letter r _System: same as above Use meaningful names r Good names: Total, Rate, length r Not so good names: ThisIsALongFORTRANname, X321, A_B_012cm, OPQ Fortran has many keywords such as INTEGER, REAL, PARAMETER, PROGRAM, END, IF, THEN, ELSE, DO, just name a few; however, Fortran does not have any reserved words. More precisely, a programmer can use these keywords as identifiers. Therefore, END, PROGRAM, DO are perfectly legal Fortran identifiers. However, this is definitely not a good practice.
Except for strings, Fortran 90 is not case sensitive. Therefore, identifier Name is identical to name, nAmE, NAme, NamE and namE. Similarly, PROGRAM is identical to program, PROgram, and progRAM. In this course, all keywords such as PROGRAM, READ, WRITE and END are in upper case and other identifiers use mixed cases.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/id.html8/5/2006 8:01:56 PM
Fortran comments
Fortran Comments
Comments should be used liberally to improve readability. The following are the rules for making comments:
q
All characters following an exclamation mark, !, except in a character string, are commentary, and are ignored by the compiler. PROGRAM TestComment1 .......... READ(*,*) Year ! read in the value of Year .......... Year = Year + 1 ! add 1 to Year .......... END PROGRAM TestComment1
An entire line may be a comment ! This is a comment line ! PROGRAM TestComment2 ......... ! This is a comment line in the middle of a program ......... END PROGRAM TestComment2
A blank line is also interpreted as a comment line. PROGRAM TestComment3 .......... READ(*,*) Count ! The above blank line is a comment line WRITE(*,*) Count + 2 END PROGRAM TestComment3
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap01/comment.html8/5/2006 8:02:03 PM
Fortran alphabets
Fortran Alphabets
Fortran only uses the following characters:
q
Letters: A N a n B O b o C P c p D Q d q E R e r F S f s G T g t H U h u I V i v J W j w K X k x L Y l y M Z m z
Digits: 0 1 2 3 4 5 6 7 8 9
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/alphabet.html8/5/2006 8:02:12 PM
If a line is ended with an ampersand, &, it will be continued on the next line. Continuation is normally to the first character of the next non-comment line. A = 174.5 * Year + Count / 100 &
Note that &is notpart of the statement. A = 174.5 * Year & ! this is a comment line + Count / 100 The above is equivalent to the following, since the commentis ignored by the compiler: A = 174.5 * Year
q
+ Count / 100
If the first non-blank character of the continuation line is &, continuation is to the first character after the &: A = 174.5 + ThisIsALong& &VariableName * 123.45 is equivalent to A = 174.5 + ThisIsALongVariableName * 123.45 In this case, there should be no spaces between the last character and the &on the first line. For example, A = 174.5 + ThisIsALong & &VariableName * 123.45 is equivalent to A = 174.5 + ThisIsALong VariableName * 123.45
Note that there are spaces between ThisIsALongand VariableName. In this way, a token (name and number) can be split over two lines. However, this is not recommended
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap01/continue.html8/5/2006 8:02:34 PM
Fortran Constants
Fortran Constants
Constants or more formally literal constants are the tokens used to denote the value of a particular type. Fortran has five types of constants: integer, real, complex, logical, and character string.
q
q q q
Integer Constants: a string of digits with an optional sign: r Correct Examples: 0, -345, 768, +12345 r Incorrect Examples: s 1,234 : comma is not allowed s 12.0: no decimal point s --4 and ++3: too many optional signs s 5- and 7+: the optional sign must precede the string of digits Real Constants: There are two representations, decimal representation and exponential representation. r Decimal Representation: A decimal point must be presented, but no commas are allowed. A real constant can have an optional sign. s Correct Examples: 23.45, .123, 123., -0.12, -.12 s Incorrect Examples: s 12,345.95: no comma is allowed s 75: real constant must have a decimal point s 123.5-: the optional sign must precede the number s $12.34: cannot use dollar sign $ r Exponential Representation: It consists of an integer or a real number in decimal representation (the mantissa or fractional part), followed by the letter E or e, followed by an integer (the exponent). s Correct Examples s 12.3456E2 or 12.3456e2: this is equal to 1234.56 s -3.14E1 or -3.14e1: this is equal to -31.4 s -1.2E-3 or -1.2e-3: this is equal to -0.0012 s 12E3 or 12e3: this is equal to 12000.0 s 0E0 or 0e0: this is equal to 0.0 s Incorrect Examples s 12.34E1.2: the exponential part must be an integer constant s 12.34-5: there is no exponential sign E or e Complex: Will not be covered in this course Logical: See Chapter 3 Character String: Character constants must be enclosed between double quotes or apostrophes (single quotes). The content of a string consists of all characters, spaces included, between the single or quote quotes, while the length of the string is the number of characters of its content. The content of a string can be zero and in this case it is an empty string r Correct Examples: s 'John' and "John": content = John and length = 4 s ' ' and " ": content = a single space and length = 1 s 'John Dow #2' and "John Dow #2": content = John Dow #2 and length = 11 s '' and "": content = nothing and length = 0 (empty string) r Incorrect Examples: s 'you and me: the closing apostrophe is missing s Hello, world': the opening apostrophe is missing s 'Hi" and "Hi': the opening and closing quotes do not match. If single quote is used in a string, then double quotes should be used to enclose the string:
Fortran Constants
"Lori's apple" This string has content Lori's apple and length 12. Alternatively, you can write the single quote twice as follows: 'Lori''s apple' The compiler will treat a pair of single quotes in the content of a string as one. Thus, the content of the above string is still Lori's apple. r Correct Examples: s 'What''s this?': content = What's this? and length = 11 s '''''': content = '' and length = 2 r Incorrect Examples: s 'Tech's seminar': the single quote between h and s should be written twice.
INTEGER: the variable is capable of holding an integer REAL: the variable is capable of holding a real number COMPLEX: the variable is capable of holding a complex number LOGICAL: the variable is capable of holding a logical value (i.e., true or false) CHARACTER: the variable is capable of holding a character string of certain length
Click here to learn the forms of these values. Click here to learn more about declaring variables.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/var-type.html8/5/2006 8:02:49 PM
INTEGER : the variables in list can hold integers REAL: the variables in list can hold real numbers COMPLEX: the variables in list can hold complex numbers LOGICAL: the variables in list can hold logical values (i.e., true or false) CHARACTER: the variables in list can hold character strings
Types INTEGER and REAL are easy. The following are examples:
q
Variables ZIP, Mean and Total are of type INTEGER: INTEGER :: ZIP, Mean, Total
Variables Average, error, sum and ZAP are of type REAL: REAL :: Average, error, sum, ZAP
Type CHARACTER is more involved. Since a string has a length attribute, a length value must be attached to character variable declarations. There are two ways to do this:
q
Use CHARACTER(LEN=i) to declare character variables of length i. For examples, r Name and Street are character variables that can hold a string of no more than 15 characters: CHARACTER(LEN=15) :: Name, Street
r
FirstName, LastName and OtherName are character variables that can hold a string of no more than 20 characters: CHARACTER(LEN=20) :: FirstName, LastName, OtehrName
Use CHARACTER(i) to declare character variables of length i. That is, there is no LEN= in the parenthesis. For examples, r Name and Street are character variables that can hold a string of no more than 15 characters: CHARACTER(15) :: Name, Street
r
FirstName, LastName and OtherName are character variables that can hold a string of no more than 20 characters:
If a variable can only hold a single character, the length part can be removed. The following three declarations are all equivalent: CHARACTER(LEN=1) CHARACTER(1) CHARACTER :: letter, digit :: letter, digit :: letter, digit
Here, variables letterand digitcan only hold no more than one character.
q
If you want to declare character variables of different length with a single statement, you can attach a length specification, *i, to the right of a variable. In this case, the corresponding variable will have the indicated length and all other variables are not affected. CHARACTER(LEN=10) :: City, Nation*20, BOX, bug*1 Here, variables Cityand BOXcan hold a string of no more than 10 characters, Nationcan hold a string of no more than 20 characters, and bugcan hold only one character.
There is one more way of specifying the length of a character variable. If the length value is replaced with a asterisk *, it means the lengths of the declared variables are determined elsewhere. In general, this type of declarations is used in subprogram arguments or in PARAMETER and is refereed to as assumed length specifier. CHARACTER(LEN=*) :: Title, Position Here, the actual lengths of variables Titleand Positionare unknown and will be determined elsewhere.
Add PARAMETER in front of the double colon (::) and use a comma to separate the type name (i.e., REAL) and the word PARAMETER Following each name, one should add an equal sign (=) followed by an expression. The value of this expression is then assigned the indicated name. After assigning a name to a value, one can use the name, rather than its value throughout the program. The compiler would convert that name to its corresponding value. It is important to note that the name assigned to a value is simply an alias of the value. Therefore, that name is not a variable. After assigning a name to a value, that name can be used in a program, even in subsequent type statements.
Examples:
q
In the example blow, Limit is a name for the integer value 30, while Max_Count is a name for the integer value 100: INTEGER, PARAMETER :: Limit = 30, Max_Count = 100
In the example below, E is a name for the real value 2.71828, while PI is a name for the real value 3.141592: REAL, PARAMETER :: E = 2.71828, PI = 3.141592
In the example below, Total and Count are names for 10 and 5, respectively. The name, Sum, is defined to be the product of the values of Total and Count and hence Sum is the name for the value 50(=10*5). INTEGER, PARAMETER :: Total = 10, Count = 5, Sum = Total*Count
In the example below, Name is a name for the string 'John' and State is a name for the string "Utah" CHARACTER(LEN=4), PARAMETER :: Name = 'John', State = "Utah" It is importantto know when assigning a name to a string: r If the string is longer, truncation to the right will happen. In the following case, since the length of the string "Smith" is 5 while the length of Name is 4, the string is truncated to the right and the content of Name is "Smit" CHARACTER(LEN=4), PARAMETER :: Name = 'Smith'
r
If the string is shorter, spaces will be added to the right. Since the string "LA" is of length 2 while the name
City is of length 4, two spaces will be padded to the right and the content of City becomes "LA " CHARACTER(LEN=4), PARAMETER :: City = "LA"
q
This is where the assumed length specifier comes in. That is, Fortran allows the length of character name to be determined by the length of s string. In the example below, names Name and City are declared to have assumed length. Since the lengths of 'John' and "LA" are 4 and 2, the length of the names Name and City are 4 and 2, respectively. CHARACTER(LEN=*), PARAMETER :: Name = 'John', City = "LA"
Variables Initialization
Variables Initialization
A variable can be considered as a box that can hold a single value. However, initially the content of a variable (or a box) is empty. Therefore, before one can use a variable, it must receive a value. Do not assume the compiler or computer will put some value, say 0, into a variable. There are at least three ways to put a value into a variable:
q q q
initializing it when the program is run using an assignment statement reading a value from keyboard or other device with a READ statement.
The way of initializing a variable is very similar to the use of PARAMETER attribute. More precisely, do the following to initial a variable with the value of an expression:
q q
add an equal sign (=) to the right of a variable name to the right of the equal sign, write an expression. It is important to note that all names in the expression must constants or names of constants.
Initializing a variable is only done exactly once when the computer loads your program into memory for execution. That is, all initializations are done before the program starts its execution. Using un-initialized variables may cause unexpected result.
Examples:
q
The following example initializes variables Offset to 0.1, Length to 10.0, and tolerance to 1.E-7. REAL :: Offset = 0.1, Length = 10.0, tolerance = 1.E-7
The following example initializes variables State1 to "MI", State2 to "MN", and State3 to "MD". CHARACTER(LEN=2) :: State1 = "MI", State2 = "MN", State3 = "MD"
The following example first defines three named integer constants with PARAMETER and uses these values to initialize two integer variables. Thus, variables Pay and Received are initialized to have values 4350 (=10*435) and 8 (3+5), respectively. INTEGER, PARAMETER :: Quantity = 10, Amount = 435, Period = 3 INTEGER :: Pay = Quantity*Amount, Received = Period+5
The following example contains a mistake. While the compiler is processing the initialization value for variable Received, the value of Period is unknown, although it will be defined on the next line. INTEGER, PARAMETER :: Quantity = 10, Amount = 435 INTEGER :: Pay = Quantity*Amount, Received = Period+5 INTEGER, PARAMETER :: Period = 3
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/var-init.html8/5/2006 8:02:53 PM
Arithmetic Operators
Arithmetic Operators
Fortran has four types of operators: arithmetic, relational, logical, and character. The following is a table of these operators, including their priority and associativity. Type Arithmetic * + Operator ** / / = Associativity right to left left to right left to right none right to left left to right left to right left to right
Relational < <= > >= == .NOT. Logical .AND. .OR. .EQV.
.NEQV.
In the table, the operator on the top-most row (**) has the highest priority (i.e., it will be evaluated first) while the operators on the bottom-most row (i.e., .EQV. and .NEQV.) have the lowest priority. The operators on the same row have the same priority. In this case, the order of evaluation is based on their associativity law. In addition to addition +, subtraction -, multiplication * and division /, Fortran has an exponential operator **. Thus, raising X to the Y-th power is written as X**Y. For example, the square of 5 is 5**2, and the square root of 5 is 5**0.5. The exponential operator has the highest priority. Operators + and - can also be used as unary operators, meaning that they only need one operand. For example, -A and +X. The former means change the sign of A, while the latter is equivalent to X. Unary operators + and - have the same priority as their binary counterparts (i.e., addition + and subtraction -). As a result, since ** is higher than the negative sign -, -3**2 is equivalent to -(3**2), which is -9. For arithmetic operators, the exponential operator ** is evaluated from right to left. Thus, A**B**C is equal to A** (B**C) rather than (A**B)**C
Click here for single mode arithmetic expressions Click here for mixed mode arithmetic expressions
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/operator.html8/5/2006 8:02:55 PM
Simple Examples:
q q q q q q q q
1 + 3 is 4 1.23 - 0.45 is 0.78 3 * 8 is 24 6.5/1.25 is 5.2 8.4/4.2 is 2.0 rather than 2, since the result must be of REAL type. -5**2 is -25 12/4 is 3 13/4 is 3 rather than 3.25. Since 13/4 is a single mode arithmetic expression and since all of its operands are of INTEGER type, the result must also be of INTEGER type. The computer will truncate the mathematical result (3.25) making it an integer. Therefore, the result is 3. 3/5 is 0 rather than 0.6.
Expressions are always evaluated from left to right If an operator is encountered in the process of evaluation, its priority is compared with that of the next one: r if the next one is lower, evaluate the current operator with its operands 3 * 5 - 4 In the above expression, in the left to right scan, operator *is encountered first. Since the the operator -is lower, 3 * 5is evaluated first transforming the given expression to 15 - 4. Hence, the result is 11.
if the next one is equal to the current, the associativity rules are used to determine which one should be evaluated. For example, if both the current and the next operators are *, then 3 * 8 * 6 will be evaluated as (3 * 8) * 6. On the other hand, if the operator is **, A ** B ** C will be evaluated as A ** (B ** C). if the next one is higher than the current, the scan should continue with the next operator. For example, consider the following expression: 4 + 5 * 7 ** 3 if the current operator is +, since the next operator *has higher priority, the scan continues to *. Once the scan arrives at *, since the next operator **is higher, 7 ** 3is evaluated first, transforming the given expression to 4 + 5 * 343 Then, the new expression is scan again. The next operator to be evaluated is *, followed by +. Thus, the original expression is evaluated as 4 + (5 * (7 ** 3)).
The result is 4 rather than 4.444444 since the operands are all integers. 2 * 4 * 5 / 3 ** 2 --> [2 * 4] * 5 / 3 ** 2 --> 8 * 5 / 3 ** 2 --> [8 * 5] / 3 ** 2 --> 40 / 3 ** 2 --> 40 / [3 ** 2] --> 40 / 9 --> 4
As in mathematics, subexpressions in parenthesis must be evaluated first. 100 + (1 --> --> --> --> --> --> --> + 250 100 + 100 + 100 + 100 + 100 + 100 + 127 / 100) ** 3 (1 + [250 / 100]) ** 3 (1 + 2) ** 3 ([1 + 2]) ** 3 3 ** 3 [3 ** 3] 27
In the following example, x**0.25 is equivalent to computing the fourth root of x. In general, taking the k-th root of x is equivalent to x**(1.0/k) in Fortran, where k is a real number. 1.0 + 2.0 * 3.0 / ( 6.0*6.0 + 5.0*44.0) ** 0.25 --> 1.0 + [2.0 * 3.0] / (6.0*6.0 + 5.0*44.0) ** 0.25
--> --> --> --> --> --> --> --> --> --> --> -->
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 2.5
+ + + + + + + + + + +
6.0 / (6.0*6.0 + 5.0*55.0) ** 0.25 6.0 / ([6.0*6.0] + 5.0*44.0) ** 0.25 6.0 / (36.0 + 5.0*44.0) ** 0.25 6.0 / (36.0 + [5.0*44.0]) ** 0.25 6.0 / (36.0 + 220.0) ** 0.25 6.0 / ([36.0 + 220.0]) ** 0.25 6.0 / 256.0 ** 0.25 6.0 / [256.0 ** 0.25] 6.0 / 4.0 [6.0 / 4.0] 1.5
The rules for evaluating mixed mode arithmetic expressions are simple:
q q
Use the rules for evaluating single mode arithmetic expressions for scanning. After locating an operator for evaluation, do the following: r if the operands of this operator are of the same type, compute the result of this operator. r otherwise, one of the operand is an integer while the other is a real number. In this case, convert the integer to a real (i.e., adding .0 at the end of the integer operand) and compute the result. Note that since both operands are real numbers, the result is a real number. There is an exception, though. In a**n, where a is a real and n is a positive integer, the result is computed by multiplying n copies of a. For example, 3.5**3 is computed as 3.5*3.5*3.5
Simple Examples:
q q q q q
1 + 2.5 is 2.5 1/2.0 is 0.5 2.0/8 is 0.25 -3**2.0 is -9.0 4.0**(1/2) is first converted to 4.0**0 since 1/2 is a single mode expression whose result is 0. Then, 4.0**0 is 1.0
An Important Note:
In expression a**b where a is REAL, the result is undefined if the value of a is negative. For example, 4.0**2 is defined with -16.0 as its result, while (-4.0)**2 is undefined.
In the following, brackets will be used to indicated the order of evaluation and braces will be used to indicated an integer-toreal conversion.
q
Note that 6.0 ** 2 is not converted to 6.0 ** 2.0. Instead, it is computed as 6.0 * 6.0. 5 * (11.0 - 5) ** 2 / 4 + 9 --> 5 * (11.0 - {5}) ** 2 / 4 + 9 --> 5 * (11.0 - 5.0) ** 2 / 4 + 9 --> 5 * ([11.0 - 5.0]) ** 2 / 4 + 9 --> 5 * 6.0 ** 2 / 4 + 9 --> 5 * [6.0 ** 2] / 4 + 9 --> 5 * 36.0 / 4 + 9 --> {5} * 36.0 / 4 + 9 --> 5.0 * 36.0 / 4 + 9 --> [5.0 * 36.0] / 4 + 9 --> 180.0 / 4 + 9 --> 180.0 / {4} + 9 --> 180.0 / 4.0 + 9 --> [180.0 / 4.0] + 9 --> 45.0 + 9 --> 45.0 + {9} --> 45.0 + 9.0 --> 54.0
In the following, 25.0 ** 1 is not converted, and 1 / 3 is zero. 25.0 ** 1 / 2 * 3.5 ** (1 / 3) --> [25.0 ** 1] / 2 * 3.5 ** (1 / 3) --> 25.0 / 2 * 3.5 ** (1 / 3) --> 25.0 / {2} * 3.5 ** (1 / 3) --> 25.0 / 2.0 * 3.5 ** (1 / 3) --> 12.5 * 3.5 ** (1 / 3) --> 12.5 * 3.5 ** ([1 / 3]) --> 12.5 * 3.5 ** 0 --> 12.5 * [3.5 ** 0] --> 12.5 * 1.0 --> 12.5
q q
The expression is evaluated first with the rules discussed in the single mode or the mixed mode expressions pages. If the type of the expression is identical to that of the variable, the result is saved in the variable. Otherwise, the result is converted to the type of the variable and saved there. r If the type of the variable is INTEGER while the type of the result is REAL, the fractional part, including the decimal point, is removed making it an integer result. r If the type of the variable is REAL while the type of the result is INTEGER, then a decimal point is appended to the integer making it a real number. Once the variable receives a new value, the original one disappears and is no more available. CHARACTER assignment follows the rules stated in the discussion of the PARAMETER attribute.
Examples:
q
The program segment below declares three INTEGER variables. The first assignment statement saves an integer value to variable Unit. The second saves a real number 100.99 into variable Amount. However, since Amount is an INTEGER variable, the real value 100.99 is converted to an integer, 100, and saved into Amount. Thus, after the second assignment completes, variable Amount holds 100. The third assignment computes the single mode expression, yielding a result 500 = 5*100. Thus, variable Total receives 500. INTEGER :: Total, Amount, Unit Unit = 5 Amount = 100.99 Total = Unit * Amount
In the following, PI is a PARAMETER and is an alias of 3.1415926. The first assignment statement puts integer value 5 into integer variable Radius. The expression in the second assignment is first evaluated, yielding a result 78.539815, which is then saved into REAL variable Area. REAL, PARAMETER :: PI = 3.1415926 REAL :: Area INTEGER :: Radius Radius = 5 Area = (Radius ** 2) * PI
In the following, Counter is an INTEGER variable initialized to zero. The meaning of the first assignment is computing the sum of the value in Counter and 1, and saves it back to Counter. Since Counter's current value is zero, Counter + 1 is 1+0 = 1 and hence 1 is saved into Counter. Therefore, the new value of Counter becomes 1 and its original value 0 disappears. The second assignment statement computes the sum of Counter's current value and 3, and saves the result back to Counter. Thus, the new value of Counter is 1+3=4. INTEGER :: Counter = 0
The following swaps the values in A and B, with the help of C. That is, after completing the following three assignment statements, A and B have 5 and 3, respectively. Initially, A and B are initialized to 3 and 5, respectively, while C is uninitialized. The first assignment statement puts A's value into C, making A=3, B=5 and C=3. The second assignment statements puts B's value into A. This destroys A's original value 3. After this, A = 5, B = 5 and C = 3. The third assignment statement puts C's value into B. This makes A=5, B=3 and C=3. Therefore, the values in A and B are exchanged. INTEGER C = A A = B B = C The following is another possible solution; but, it uses one more variable. INTEGER :: A = 3, B = 5, C, D C D A B = = = = A B D C :: A = 3, B = 5, C
An Important Note:
A name declared with the PARAMETER attribute is an alias of a value and is not a variable. Therefore, it cannot be used on the left-hand side of =, although it can be used on the right-hand side. The following is wrong!
InchToCM = factor * X
the name and meaning of the function such as ABS() and SQRT() the number of arguments the range of the argument the types of the arguments the type of the return value or the function value
For example, function SQRT() accepts a REAL argument whose value must be non-negative and computes and returns the square root of the argument. Therefore, SQRT(25.0) returns the square root of 25.0 and SQRT(-1.0) would cause an error since the argument is negative.
q
Mathematical functions: Return Type REAL REAL REAL REAL REAL REAL REAL REAL REAL REAL
Function ABS(x)
Arg. Type
INTEGER INTEGER REAL REAL REAL REAL REAL REAL REAL REAL REAL REAL
SQRT(x) square root of x SIN(x) COS(x) TAN(x) ASIN(x) ACOS (x) ATAN (x) EXP(x) LOG(x) sine of x radian cosine of x radian tangent of x radian arc sine of x arc cosine of x arc tangent of x exp(x) natural logarithm of x
Note that all trigonometric functions use radian rather than degree for measuring angles. For function ATAN(x), x must be in (-PI/2, PI/2). For ASIN(x) and ACOS(x), x must be in [-1,1].
q
Function
Meaning
Arg. Type
integer part x nearest integer to x greatest integer less than or equal to x the fractional part of x convert x to REAL
Arg. Type
MIN(x1, x2, ..., xn) minimum of x1, x2, ... xn MOD(x,y) remainder x - INT(x/y) *y
Functions in an Expression:
q q
Functions have higher priority than any arithmetic operators. All arguments of a function can be expressions. These expressions are evaluated first and passed to the function for computing the function value. The returned function value is treated as a value in the expression.
An Example:
The example below has three initialized variables A, B and C. The result is computed and saved into uninitialized variable R. REAL REAL :: :: A = 1.0, B = -5.0, C = 6.0 R
R = (-B + SQRT(B*B - 4.0*A*C))/(2.0*A) The following uses brackets to indicated the order of evaluation: (-B + SQRT(B*B - 4.0*A*C))/(2.0*A) --> ([-B] + SQRT(B*B - 4.0*A*C))/(2.0*A)
--> --> --> --> --> --> --> --> --> --> --> --> --> --> -->
(5.0 + SQRT(B*B - 4.0*A*C))/(2.0*A) (5.0 + SQRT([B*B] - 4.0*A*C))/(2.0*A) (5.0 + SQRT(25.0 - 4.0*A*C))/(2.0*A) (5.0 + SQRT(25.0 - [4.0*A]*C))/(2.0*A) (5.0 + SQRT(25.0 - 4.0*C))/(2.0*A) (5.0 + SQRT(25.0 - [4.0*C))/(2.0*A) (5.0 + SQRT(25.0 - 24.0))/(2.0*A) (5.0 SQRT([25.0 - 24.0]))/(2.0*A) (5.0 + SQRT(1.0))/(2.0*A) (5.0 + 1.0)/(2.0*A) ([5.0 + 1.0])/(2.0*A) 6.0/(2.0*A) 6.0/([2.0*A]) 6.0/2.0 3.0
The first form starts with READ(*,*), followed by a list of variable names, separated by commas. The computer will read values from the keyboard successively and puts the value into the variables. The second form only has READ(*,*), which has a special meaning.
q
The following example reads in four values into variables Factor, N, Multiple and tolerance in this order. INTEGER REAL READ(*,*) :: :: Factor, N Multiple, tolerance Factor, N, Multiple, tolerance
The following example reads in a string into Title, followed by three real numbers into Height, Length and Area. CHARACTER(LEN=10) REAL READ(*,*) :: Title :: Height, Length, Area
If a READ statement needs some input values, start a new line that contains the input. Make sure the type of the input value and the type of the corresponding variable are the same. The input data values must be separated by space or commas. For the following READ CHARACTER(LEN=5) REAL INTEGER READ(*,*) :: Name :: height, length :: count, MaxLength
The input data may look like the following: "Smith" 100.0 25 123.579 10000
Note that all input data are on the same line and separated with spaces. After reading in this line, the contents of the variables are Name height count length MaxLength
q
Input values can be on several lines. As long as the number of input values and the number of variables in the corresponding READ agree, the computer will search for the input values. Thus, the following input should produce the same result. Note that even blank lines are allowed in input. "Smith" 25 123.579 10000 100.0
The execution of a READ always starts searching for input values with a new input line. INTEGER READ(*,*) READ(*,*) READ(*,*) :: I, J, K, L, M, N
I, J K, L, M N
If the above READstatements are used to read the following input lines, 100 200 300 400 500 600 then I, J, K, L, Mand Nwill receive 100, 200, 300, 400, 500 and 600, respectively. Consequently, if the number of input values is larger than the number of variables in a READ statement, the extra values will be ignored. Consider the following: INTEGER READ(*,*) READ(*,*) If the input lines are 100 200 300 400 :: I, J, K, L, M, N I, J, K L, M, N
500 900
600
700
800
Variables I, Jand Kreceive 100, 200 and 300, respectively. Since the second READstarts with a new line, L, Mand Nreceive 500, 600 and 700, respectively. 400 on the first input line is lost. The next READwill start reading with the third line, picking up 900. Hence, 800 is lost. A limited type conversion is possible in a READ statement. If the input value is an integer and the corresponding variable is of REAL type, the input integer will be convert to a real number. But, if the input value is a real number and the corresponding variable is of INTEGER type, an error will occur. The length of the input string and the length of the corresponding CHARACTER variable do not have to be equal. If they are not equal, truncation or padding with spaces will occur as discussed in the PARAMETER attribute page. Finally, a READ without a list of variables simply skips a line of input. Consider the following: INTEGER READ(*,*) READ(*,*) READ(*,*) If the input lines are 100 400 700 200 500 800 300 600 900 :: P, Q, R, S P, Q R, S
The first READreads 100 and 200 into Pand Qand 300 is lost. The second READstarts with a new input line, which is the second one. It does not read in anything. The third READstarts with the third line and reads 700 and 800 into Rand S. As a result, the three input values (i.e., 400, 500 and 600) are all lost. The third value on the third line, 900, is also lost.
The first form starts with WRITE(*,*), followed by a list of arithmetic expressions or character strings, separated by commas. The computer will evaluate the arithmetic expressions and displays the results. Note that if a variable does not contain a value, its displayed result is unpredictable. The second form only has WRITE(*,*), which has a special meaning.
q
The following example displays the values of four variables on screen: INTEGER REAL :: :: Factor, N Multiple, tolerance Factor, N, Multiple, tolerance
WRITE(*,*)
q
The following example displays the string content of Title, followed by the result of (Height + Length) * Area. CHARACTER(LEN=10) REAL WRITE(*,*) :: Title :: Height, Length, Area
Each WRITE starts with a new line. Consequently, the second form in which the WRITE does not have a list of expressions just displays a blank line. INTEGER :: REAL :: CHARACTER(LEN=*), PARAMETER :: Target Angle, Time = IS = UNIT =
Distance "The time to hit target " " is " " sec."
& &
Target = 10 Angle = 20.0 Distance = 1350.0 WRITE(*,*) 'Angle = ', Angle WRITE(*,*) 'Distance = ', Distance WRITE(*,*) WRITE(*,*) Time, Target, IS, Angle * Distance, UNIT
This example may produce the following result: Angle = 20.0 Distance = 1350.0 The time to hit target 10 is 27000sec. The blank line is generated by the third WRITE. The above example uses assumed length specifier (i.e., LEN=*) and continuation lines (i.e., symbol &).
q
If there are too many results that cannot be fit into a single line, the computer will display remaining results on the second, the third line and so on.
Output Format:
There is nothing to worry about the output format. The computer will use the best way to display the results. In other words, integers and real numbers will be displayed as integers and real numbers. But, only the content of a string will be displayed. The computer will also guarantee that all significant digits will be shown so that one does not have to worry how many positions should be used for displaying a number. The consequence is that displaying a good-looking table is a challenge. This will be discussed in FORMAT statement.
A**B**C is not equal to (A**B)**C. Dividing an integer with another integer always yields an integer result. In PARAMETER, assignment statement and READ, strings may be truncated if the length of the variable at the receiving end is not long enough.
Solution
! -----------------------------------------------------------! This program illustrates the following points: ! (1) The exponential trap: ! That is, A**B**C is equal to A**(B**C) rather ! than (A**B)**C. ! (2) The integer division trap: ! That is, 4/6 is ZERO in Fortran rather than ! a real number 0.666666 ! Function REAL() is used to illustrate the ! differences. ! (3) The string truncation trap: ! What if the length assigned to a CHARACTER ! is shorter than the length of the string you ! expect the identifier to have? The third part ! shows you the effect. ! -----------------------------------------------------------PROGRAM IMPLICIT Fortran_Traps NONE :: :: :: :: :: A O M X Y = = = = = 2, B = 2, H = 3 4, P = 6 'Smith', N = 'TEXAS' 'Smith' 'TEXAS'
INTEGER, PARAMETER INTEGER, PARAMETER CHARACTER(LEN=5), PARAMETER CHARACTER(LEN=4), PARAMETER CHARACTER(LEN=6), PARAMETER ! The exponential trap WRITE(*,*) WRITE(*,*) WRITE(*,*)
"First, the exponential trap:" A, ' ** ', B, ' ** ', H, ' = ', A**B**H '( ', A, ' ** ', B, ' ) **', H, ' = ', (A**B)**H
WRITE(*,*) WRITE(*,*) ! !
The integer division trap. Intrinsic function REAL() converts an integer to a real number WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) "Second, the integer division trap:" O, ' / ', P, ' = ', O/P 'REAL( ', O, ' ) / ', P, ' = ', REAL(O)/P O, ' / REAL( ', P, ' ) = ', O/REAL(P)
The string truncation trap WRITE(*,*) WRITE(*,*) WRITE(*,*) "Third, the string truncation trap:" 'IS ', M, ' STILL IN ', N, '?' 'IS ', X, ' STILL IN ', Y, '?' Fortran_Traps
END PROGRAM
Program Output
First, 2 ** 2 ( 2 ** 2 ** ( the exponential trap: ** 3 = 256 2 ) **3 = 64 2 ** 3 ) = 256
Second, the integer division trap: 4 / 6 = 0 REAL( 4 ) / 6 = 0.666666687 4 / REAL( 6 ) = 0.666666687 Third, the string truncation trap: IS Smith STILL IN TEXAS? IS Smit STILL IN TEXAS ?
Discussion
q q
All names in this program are aliases of constants. Consider the first group. Variables A, B and H are aliases of 2, 2 and 3. The first WRITE computes A**B**H, which is equivalent to A**(B**H), and the result is 2**(2**3)=256. The second WRITE computes (A**B)**C and the result is (2**2)**3=64. The third WRITE computes A**(B**H) and the result is 2**(2**3)=256. Thus, it is
clear that A**B**H equal to A**(B**H). The second group illustrates the problem unique to integer division. Two integer aliases are involved, namely O and P with values 4 and 6, respectively. The first WRITE displays O/P and the result is 4/6=0 since it is an integer division. The second WRITE converts O to real with intrinsic function REAL(). Thus, in computing REAL(O)/P, the expression is REAL(4)/6, which becomes 4.0/6 and then 4.0/6.0. Thus, the result is 0.6666667. The third WRITE should give the same result. Go back to the top of this program. Alias M and N should have no problem since the length of the names and the length of the strings agree. Since the length of X is 4 and is shorter than the length of string 'Smith', X only receives the left-most 4 characters. Now take a look at Y. Since the length of Y is longer than the length of string 'TEXAS', spaces will be appended to the end to fill up to 6 characters. Thus, Y actually becomes 'TEXAS '. The output should look like the following: IS Smith STILL IN TEXAS? IS Smit STILL IN TEXAS ? On the second line, it is easily seen that the original Smithbecomes Smitand the original TEXASbecomes TEXAS_, where _indicates a space.
Write a program to compute and display the means of three REAL variables initialized with positive real values.
Solution
! ------------------------------------------------------! Computes arithmetic, geometric and harmonic means ! ------------------------------------------------------PROGRAM ComputeMeans IMPLICIT NONE REAL REAL :: X = 1.0, Y = 2.0, Z = 3.0 :: ArithMean, GeoMean, HarmMean 'Data items: ', X, Y, Z
WRITE(*,*) WRITE(*,*)
ArithMean = (X + Y + Z)/3.0 GeoMean = (X * Y * Z)**(1.0/3.0) HarmMean = 3.0/(1.0/X + 1.0/Y + 1.0/Z) WRITE(*,*) WRITE(*,*) WRITE(*,*) 'Arithmetic mean = ', ArithMean 'Geometric mean = ', GeoMean 'Harmonic Mean = ', HarmMean
Program Output
Data items: 1., 2., 3.
Discussion
q
q q
Variables X, Y and Z are initialized in the first REAL statement, while the second declares three variables, ArithMean, GeoMean and HarmMean, for holding the result. The first WRITE statement displays the values of X, Y and Z. The second WRITE generates a blank line. In the second assignment statement that computes the geometric mean, the exponent part is 1.0/3.0 instead of 1/3, since the latter is zero. 1.0/3 and 1.0/3 also work fine. But, you should not use 0.3, since it is not equal to 1/3. The parenthesis surrounding X * Y * Z cannot be removed; otherwise, the expression X * Y * Z **(1.0/3.0) means X * Y * (Z **(1.0/3.0)) since ** has a priority higher than that of *. The parenthesis in the third assignment cannot be removed either. Why?
if b*b-4*a*c is non-negative, the roots of the equation can be computed with the following formulae:
Write a program to read in the coefficients a, b and c, and compute and display the roots. You can assume that b*b - 4*a*c is always non-negative.
Solution
! --------------------------------------------------! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0 ! --------------------------------------------------PROGRAM QuadraticEquation IMPLICIT NONE REAL REAL REAL ! :: a, b, c :: d :: root1, root2
root1 = (-b + d)/(2.0*a) root2 = (-b - d)/(2.0*a) ! display the results WRITE(*,*) WRITE(*,*) END PROGRAM
Program Output
A, B, C Please : 1.0 -5.0 3.0 Roots are 4.30277538 and 0.697224379 The input to the above problem consists of three real numbers, 1.0, -5.0 and 3.0, and the computed roots are 4.30277538 and 0.697224379.
Discussion
q
The WRITE displays a message like this A, B, C Please : After displaying this message, the computer executes READ. Since there is no input value, it will wait until the user types in three real values and hits the Returnkey. Then, these values are stored in a, band c. The first assignment statement computes the square root of the discriminant (i.e., b*b - 4.0*a*c) and stores it into variable d. The roots are computed with the second and third assignments. Note that the parenthesis surrounding 2.0*a cannot be removed; otherwise, it is equivalent to ((-b + d)/2.0)*a, which is wrong. The last two WRITE statements display the roots.
Write a program to read in the values of base and height, and use the above formula to compute the length of the parabola segment. Note that both base and height values must be positive.
Solution
! ----------------------------------------------------------! Calculate the length of a parabola given height and base. * ! ----------------------------------------------------------PROGRAM ParabolaLength IMPLICIT NONE REAL REAL :: Height, Base, Length :: temp, t 'Height of a parabola : ' Height 'Base of a parabola Base : '
! ... temp and t are two temporary variables t = 2.0 * Height temp = SQRT(t**2 + Base**2) Length = temp + Base**2/t*LOG((t + temp)/Base) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) END PROGRAM
'Height = ', Height 'Base = ', Base 'Length = ', Length ParabolaLength
Program Output
Height of a parabola : 100.0 Base of a parabola 78.5 Height = 100. Base = 78.5 Length = 266.149445 The input values for Height and Base are 100.0 and 78.5, respectively. The computed length is 266.149445. :
Discussion
q
The values of base and height will be stored in REAL variables Base and Height, respectively. Length will be used to store the parabola segment length. Since the content in the square root is used twice, it would be more convenient to save the result in a variable. This value will be stored in temp. Since 2h also appears a few times, variable t is used to store this value. After reading in Height and Base, 2.0 * Height is computed and stored in t with the first assignment. Then, the second assignment computes the content in the square root and stores the result into temp. The third assignment compute the segment length and stores the result into Length. Note that intrinsic function LOG () is used. The four WRITE statements display the input and the results.
The horizontal and vertical components of the velocity vector are computed as
Finally, the angle between the ground and the velocity vector is determined by the formula below:
Write a program to read in the launch angle a, the time since launch t, and the launch velocity u, and compute the position, the velocity and the angle with the ground.
Solution
! ! ! ! ! ! -------------------------------------------------------------------Given t, the time since launch, u, the launch velocity, a, the initial angle of launch (in degree), and g, the acceleration due to gravity, this program computes the position (x and y coordinates) and the velocity (magnitude and direction) of a projectile. --------------------------------------------------------------------
PROGRAM Projectile IMPLICIT NONE REAL, PARAMETER :: g = 9.8 REAL, PARAMETER :: PI = 3.1415926 REAL REAL REAL REAL REAL REAL REAL REAL REAL READ(*,*) Angle X Y Vx Vy V Theta = = = = = = = :: :: :: :: :: :: :: :: :: Angle Time Theta U V Vx Vy X Y ! acceleration due to gravity ! you knew this. didn't you ! ! ! ! ! ! ! ! ! launch angle in degree time to flight direction at time in degree launch velocity resultant velocity horizontal velocity vertical velocity horizontal displacement vertical displacement
Angle, Time, U
Angle * PI / 180.0 ! convert to radian U * COS(Angle) * Time U * SIN(Angle) * Time - g*Time*Time / 2.0 U * COS(Angle) U * SIN(Angle) - g * Time SQRT(Vx*Vx + Vy*Vy) ATAN(Vy/Vx) * 180.0 / PI 'Horizontal displacement 'Vertical displacement 'Resultant velocity 'Direction (in degree) Projectile : : : : ', ', ', ', X Y V Theta
Program Output
If the input to the program consists of the following three real values: 45.0 6.0 60.0
The program will generate the following output: Horizontal displacement Vertical displacement Resultant velocity Direction (in degree) : : : : 254.558472 78.158432 45.4763107 -21.1030636
Discussion
q q
q q q q
The program uses Angle for the angle a, Time for t, and U for u. The READ statement reads the input. The first assignment statement converts the angle in degree to radian. This is necessary since all intrinsic trigonometric functions use radian rather than degree. Variables X and Y, which are computed in the second and third assignments, hold the displacements. The next two assignments compute the components of the velocity vector. The velocity itself is computed in the sixth assignment. Finally, the angle with ground, Theta, is computed with the last assignment. Note that ithe result is converted back to degree, since ATAN(x) returns the arc tangent value of x in radian.
:: John = "John", Sam = "Sam" :: Lori = "Lori", Reagan = "Reagan" :: Ans1, Ans2, Ans3, Ans4
= = = =
q q
Variable Ans1 contains a string "JohnLori**", where * denotes a space. These two spaces come from variable Lori since its content is "Lori**". Variable Ans2 contains a string "Sam Reagan". The space in the string comes from variable Sam since its content is "Sam*", where, as above, * denotes a space. Variable Ans3 contains a string "ReaganSam*". Variable Ans4 contains a string "Lori**Sam*".
Substrings
A consecutive part of a string is called a substring. One can append the extent specifier at the end of a CHARACTER variable to indicate a substring. An extent specifier has a form of ( integer-exp1 : integer-exp2 ) It starts with a (, followed by an integer expression, followed by a colon :, followed by another integer expression, followed by ). The first integer indicates the first position of the substring, while the second integer indicates the last position of the substring. Therefore, (3:5) means the substring consists of the third, fourth and fifth characters. If the content of variable String is "abcdefghijk", then String(3:5) is a string "cde". If the first integer expression is missing, the value is assumed to be 1. If the second integer expression is missing, the value is assumed to be the last character of the string. Continue with the example in previous paragraph. String(:4) is string "abcd". String(2+5:) is string "ghijk".
As a good programming practice, the value of the first integer expression should be greater than or equal to 1, and the value of the second integer expression should be less than of equal to the length of the string. A string variable with an extent specifier can be used on the left-hand side of an assignment. Its meaning is assigning the string content on the right-hand side into the substring part of the string variable. Let the content of a string variable LeftHand of length 10 be "1234567890". The following are a few examples:
q q q q q
LeftHand(3:5) = "abc": the new content of LeftHand is "12abc67890". LeftHand(1:6) = "uvwxyz": the new content of LeftHand is "uvwxyz7890". LeftHand(:6) = "uvzxyz": the result is identical to the previous example. LeftHand(4:) = "lmnopqr": the new content of LeftHand is "123lmnopqr". LeftHand(3:8) = "abc": the new content of LeftHand is "12abc***90", where * denotes a space. Note that since LeftHand(3:8) consists of 6 character positions and "abc" has only three characters, the remaining will be filled with spaces. LeftHand(4:7) = "lmnopq": the new content of LeftHand is "123lmno890". It is due to truncation.
Example
! ---------------------------------------------------------------! This program uses DATE_AND_TIME() to retrieve the system date ! and the system time. Then, it converts the date and time ! information to a readable format. This program demonstrates ! the use of concatenation operator // and substring ! ---------------------------------------------------------------PROGRAM DateTime IMPLICIT NONE CHARACTER(LEN = 8) CHARACTER(LEN = 4) :: DateINFO :: Year, Month*2, Day*2 ! ccyymmdd
CHARACTER(LEN = 10) :: TimeINFO, PrettyTime*12 CHARACTER(LEN = 2) :: Hour, Minute, Second*6 CALL ! ! ! DATE_AND_TIME(DateINFO, TimeINFO)
! hhmmss.sss
decompose DateINFO into year, month and day. DateINFO has a form of ccyymmdd, where cc = century, yy = year mm = month and dd = day Year = DateINFO(1:4) Month = DateINFO(5:6) Day = DateINFO(7:8) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) 'Date information -> ', DateINFO ' Year -> ', Year ' Month -> ', Month ' Day -> ', Day
! ! !
decompose TimeINFO into hour, minute and second. TimeINFO has a form of hhmmss.sss, where h = hour, m = minute and s = second Hour = TimeINFO(1:2) Minute = TimeINFO(3:4) Second = TimeINFO(5:10) PrettyTime = Hour // ':' // Minute // ':' // Second WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*)
'Time Information -> ', TimeINFO ' Hour -> ', Hour ' Minite -> ', Minute ' Second -> ', Second ' Pretty Time -> ', PrettyTime
the substring operator can be used on the left-hand side. PrettyTime = ' ' PrettyTime( :2) = PrettyTime(3:3) = PrettyTime(4:5) = PrettyTime(6:6) = PrettyTime(7: ) = WRITE(*,*) WRITE(*,*)
' DateTime
END PROGRAM
Program Output
Date information Year Month Day Time Information Hour Minite Second Pretty Time -> -> -> -> -> -> -> -> -> 19970811 1997 08 11 010717.620 01 07 17.620 01:07:17.620
Discussion
q
Subroutine DATE_AND_TIME() returns the date of time and day information into two character arguments. The first one, DateINFO, must have a length of at least 8. The returned value is in the form of ccyymmdd, where cc gives the century, yy the year, mm the month, and dd the day. If today is August 11, 1997, the call to this subroutine returns a string of eight characters "19970811" The second argument, TimeINFO, will receive a string of 12 characters with a form of hhmmss.sss, where hh gives the hour value, mm the minute value, and ss.sss the second value. Thus, if the time this subroutine is called is 1 after 7 minutes and 17.620 seconds, the returned value is "010717.620"
Selective Execution
Selective Execution
Select the topics you wish to review:
Selective Execution LOGICAL Type and Variables LOGICAL Input and Output Relational Operators LOGICAL Operators and Expressions IF-THEN-ELSE-END IF Statement Form 1: IF-THEN-ELSE-END IF Form 2: IF-THEN-END IF Form 3: Logical IF Programming Example 1: Quadratic Equation Solver Programming Example 2: Final Mark Computation Programming Example 3: Heron's Formula for Computing Triangle Area Nested IF-THEN-ELSE-END IF IF-THEN-ELSE IF-END IF Programming Examples: Quadratic Equation Solver: Again Quadratic Equation Solver: Revisited Sort Three Numbers SELECT CASE Statement Programming Example 1: Computing Letter Grade Programming Example 2: Character Testing Download my course overheads
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/select.html8/5/2006 8:04:19 PM
Answer, Condition, Test, Value and Yes_and_No are LOGICAL variables that can hold either .TRUE. or . FALSE.: LOGICAL LOGICAL :: Answer, Condition, Test :: Value, Yes_and_No
LOGICAL identifiers Answer and Condition are aliases of .TRUE. and .FALSE., respectively: LOGICAL, PARAMETER :: Answer = .TRUE., Condition = .FALSE.
LOGICAL variables Test and PreTest are initialized to .TRUE. and .FALSE., respectively: LOGICAL :: Test = .TRUE., PreTest = .FALSE.
LOGICAL variables Cond_1, Cond_2 and Total are assigned with .TRUE., .TRUE. and .FALSE., respectively: LOGICAL :: Cond_1, Cond_2, Total
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/log-type.html8/5/2006 8:04:23 PM
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/log-io.html8/5/2006 8:04:25 PM
Relational Operators
Relational Operators
There are six relational operators:
q q q q q q
< : less than <= : less than or equal to > : greater than >= : greater than or equal to == : equal to /= : not equal to
q q
Each of these six relational operators takes two operands. These two operands must both be arithmetic or both be strings. For arithmetic operands, if they are of different types (i.e., one INTEGER and the other REAL), the INTEGER operand will be converted to REAL. The outcome of a comparison is a LOGICAL value. For example, 5 /= 3 is .TRUE. and 7 + 3 >= 20 is .FALSE. All relational operators have equal priority and are lower than those of arithmetics operators as shown in the table below: Type Arithmetic * + Operator ** / / = Associativity right to left left to right left to right none
This means that a relational operator can be evaluated only if its two operands have been evaluated. For example, in a + b /= c*c + d*d expressions a+b and c*c + d*d are evaluated before the relational operator /= is evaluated. If you are not comfortable in writing long relational expressions, use parenthesis. Thus, 3.0*SQRT(Total)/(Account + Sum) - Sum*Sum >= Total*GNP - b*b is equivalent to the following: (3.0*SQRT(Total)/(Account + Sum) - Sum*Sum) >= (Total*GNP - b*b)
q
Although a < b < c is legal in mathematics, you cannot write comparisons this way in Fortran. The meaning of this expression is a < b and b < c. You should use logical operator to achieve this.
Relational Operators
Examples
q q
3**2 + 4**2 == 5**2 is .TRUE. If the values of REAL variables a, b and c are 1.0, 2.0 and 4.0, respectively, then b*b - 4.0*a*c >= 0.0 is equivalent to 2.0*2.0 - 4.0*1.0*4.0 >= 0.0, which evaluates to -12.0 >= 0.0. Thus, the result is .FALSE. If REAL variables x and y have values 3.0 and 7.0, and INTEGER variables p and q have values 6 and 2, what is the result of x*x - y*y + 2.0*x*y /= p*q + p**3 - q**3? x*x - y*y + 2.0*x*y /= p*q + p**3 - q**3 --> 3.0*3.0 - 7.0*7.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> [3.0*3.0] - 7.0*7.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> 9.0 - 7.0*7.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> 9.0 - [7.0*7.0] + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> 9.0 - 49.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> [9.0 - 49.0] + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> -40.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3 --> -40.0 + [2.0*3.0]*7.0 /= 6*2 + 6**3 - 2**3 --> -40.0 + 6.0*7.0 /= 6*2 + 6**3 - 2**3 --> -40.0 + [6.0*7.0] /= 6*2 + 6**3 - 2**3 --> -40.0 + 42.0 /= 6*2 + 6**3 - 2**3 --> [-40.0 + 42.0] /= 6*2 + 6**3 - 2**3 --> 2.0 /= 6*2 + 6**3 - 2**3 --> 2.0 /= [6*2] + 6**3 - 2**3 --> 2.0 /= 12 + 6**3 - 2**3 --> 2.0 /= 12 + [6**3] - 2**3 --> 2.0 /= 12 + 216 - 2**3 --> 2.0 /= [12 + 216] - 2**3 --> 2.0 /= 228 - 2**3 --> 2.0 /= 228 - [2**3] --> 2.0 /= 228 - 8 --> 2.0 /= [228 - 8] --> 2.0 /= [220] --> 2.0 /= 220.0 --> .TRUE. In the above, please note the left-to-right evaluation order and the type conversion making 220 to 220.0 before carrying out /=
Relational Operators
< N < O < P < Q < R < S < T < U < V < W < X < Y < Z a < b < c < d < e < f < g < h < i < j < k < l < m < n < o < p < q < r < s < t < u < v < w < x < y < z 0 < 1 < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 If you compare characters in different sequences such as 'A' < 'a' and '2' >= 'N', you are asking for trouble since different encoding methods may produce different answers. Moreover, do not assume there exists a specific order among upper and lower case letters, digits, and special symbols. Thus, '+' <= 'A', '*' >= '%', 'u' > '$', and '8' >= '?' make no sense. However, you can always compare if two characters are equal or not equal. Hence, '*' /= '9', 'a' == 'B' and '8' == 'b' are perfectly fine. Here is the method for comparing two strings:
q q q
The comparison always starts at the first character and proceeds from left to right. If the two corresponding characters are equal, then proceed to the next pair of characters. Otherwise, the string containing the smaller character is considered to be the smaller one. And, the comparison halts. During the process comparison, if r both strings have consumed all of their characters, they are equal since all of their corresponding characters are equal. r otherwise, the shorter string is considered to be the smaller one.
Examples
q
Compare "abcdef" and "abcefg" a b c d e f = = = < a b c e f g The first three characters of both strings are equal. Since 'd' of the first string is smaller than 'e' of the second, "abcdef" < "abcefg" holds. Compare "01357" and "013579" 0 1 3 5 7 = = = = = 0 1 3 5 7 9 Since all compared characters are equal and the first string is shorter, "01357" < "013579" holds. What is the result of "DOG" < "FOX"? D O G < F O X
Relational Operators
The first character (i.e., 'D' < 'F') determines the outcome. That is, "DOG" < "FOX" yields .TRUE.
A Special Note
The priority of all six relational operators is lower than the string concatenation operator //. Therefore, if a relational expression involves //, then all string concatenations must be carried out before evaluating the comparison operator. Here is an example: "abcde" // "xyz" < "abc" // ("dex" // "ijk") --> ["abcde" // "xyz"] < "abc" // ("dex" // "ijk") --> "abcdexyz" < "abc" // ("dex" // "ijk") --> "abcdexyz" < "abc" // (["dex" // "ijk"]) --> "abcdexyz" < "abc" // ("dexijk") --> "abcdexyz" < "abc" // "dexijk" --> "abcdexyz" < ["abc" // "dexijk"] --> "abcdexyz" < "abcdexijk" --> .FALSE.
.NOT. : logical not .AND. : logical and .OR. : logical or .EQV. : logical equivalence .NEQV. : logical not equivalence
The following is a table of these operators, including there priority and associativity. Type Arithmetic * + Operator ** / / = Associativity right to left left to right left to right none right to left left to right left to right left to right
Relational < <= > >= == .NOT. Logical .AND. .OR. .EQV.
.NEQV.
Truth Tables
The evaluation of logical expressions is determined by truth tables. Let us start with the .NOT. operator. Operand Result
. . .TRUE. NOT. FALSE. .FALSE. .TRUE. Note that .NOT. is a unary operator. Therefore, .NOT. a yields .TRUE. (resp., .FALSE.) if the value of LOGICAL variable a is .FALSE. (resp., .TRUE.).
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/logical.html (1 of 5)8/5/2006 8:04:39 PM
The following is the truth table of .AND.: .AND. .TRUE. .TRUE. .FALSE .TRUE. . FALSE.
. . . FALSE. FALSE. FALSE. Therefore, the result of logical expression a .AND. b is .TRUE. if and only if both operands a and b are .TRUE.. In all other cases, the result is always .FALSE.
The following is the truth table of .OR.: . .FALSE TRUE. . .TRUE. TRUE.
.OR. .TRUE.
. . . FALSE. TRUE. FALSE. Therefore, the result of logical expression a .OR. b is .FALSE. if and only if both operands a and b are .FALSE.. In all other cases, the result is always .TRUE. In other words, if one of the two operands of the .OR. operator is .TRUE., the result is .TRUE.
The following is the truth table of .EQV.: .EQV. .TRUE. .TRUE. .FALSE .TRUE. . FALSE.
. . .TRUE. FALSE. FALSE. Therefore, the result of logical expression a .EQV. b is .TRUE. if and only if both operands a and b have the same value (i. e., both are .TRUE. or both are .FALSE.). As mentioned in relational expressions, relational operators can only compare arithmetic values and cannot be used to compare logical values. To compare if two logical values are equal, use .EQV.
.TRUE.
. .TRUE. FALSE.
. . .TRUE. FALSE. FALSE. Therefore, the result of logical expression a .NEQV. b is .TRUE. if and only if both operands a and b do not have the same value. As mentioned in relational expressions, relational operators can only compare arithmetic values and cannot be used to compare logical values. To compare if two logical values are not equal, use .NEQV. Note that .NEQV is the opposite of . EQV.. Hence, to test if logical variables x and y have different values, one can use .NOT. (x .EQV. y). Here, if x and y have the same value, x .EQV. y is .TRUE. and .NOT. (x .EQV. y) is .FALSE. On the other hand, if x and y have different values, x .EQV. y is .FALSE. and .NOT. (x .EQV. y) is .TRUE.
Priority
The priority of .NOT. is the highest, followed by .AND., followed by .OR., followed by .EQV. and .NEQV. Note that . NOT. is right associative, while the other four are left associative. Here are some examples:
q
Let LOGICAL variables Something and Another have values .TRUE. and .FALSE., respectively. .NOT. Something .AND. Another --> .NOT. .TRUE. .AND. .FALSE. --> [.NOT. .TRUE.] .AND. .FALSE. --> .FALSE. .AND. .FALSE. --> .FALSE.
In the above, since .NOT.has the highest priority, it is evaluated first. Now, look at the following example: .NOT. (Something .AND. Another) --> .NOT. (.TRUE. .AND. .FALSE.) --> .NOT. ([.TRUE. .AND. .FALSE.]) --> .NOT. .FALSE. --> .TRUE.
Let LOGICAL variables a, b and c have values .TRUE., .TRUE. and .FALSE., respectively. .NOT. a --> --> --> --> --> --> --> --> .OR. .NOT. b .AND. c .NOT. .TRUE. .OR. .NOT. .TRUE. .AND. .FALSE. [.NOT. .TRUE.] .OR. .NOT. .TRUE. .AND. .FALSE. .FALSE. .OR. .NOT. .TRUE. .AND. .FALSE. .FALSE. .OR. [.NOT. .TRUE.] .AND. .FALSE. .FALSE. .OR. .FALSE. .AND. .FALSE. .FALSE. .OR. [.FALSE. .AND. .FALSE.] .FALSE. .OR. .FALSE. .FALSE.
Let INTEGER variable n have a value of 4: n**2 + 1 --> --> --> --> --> --> --> --> --> --> --> --> > 10 .AND. .NOT. n < 3 4**2 + 1 > 10 .AND. .NOT. 4 [4**2] + 1 > 10 .AND. .NOT. 16 + 1 > 10 .AND. .NOT. 4 < [16 + 1] > 10 .AND. .NOT. 4 17 > 10 .AND. .NOT. 4 < 3 [17 > 10] .AND. .NOT. 4 < 3 .TRUE. .AND. .NOT. 4 < 3 .TRUE. .AND. .NOT. [4 < 3] .TRUE. .AND. .NOT. .FALSE .TRUE. .AND. [.NOT. .FALSE] .TRUE. .AND. .TRUE. .TRUE.
Note that the above expression, if you like, can be rewritten with parentheses as follows: (n**2 + 1 > 10) .AND. .NOT. (n < 3)
q
Let INTEGER variables m, n, x and y have values 3, 5, 4 and 2, respectively: .NOT. (m --> --> --> --> --> --> --> --> --> --> --> --> --> --> --> --> --> > n .AND. x < y) .NEQV. (m <= n .AND. x >= y) .NOT. (3 > 5 .AND. 4 < 2) .NEQV. (3 <= 5 .AND. 4 >= 2) .NOT. ([3 > 5] .AND. 4 < 2) .NEQV. (3 <= 5 .AND. 4 >= 2) .NOT. (.FALSE. .AND. 4 < 2) .NEQV. (3 <= 5 .AND. 4 >= 2) .NOT. (.FALSE. .AND. [4 < 2]) .NEQV. (3 <= 5 .AND. 4 >= 2) .NOT. (.FALSE. .AND. .FALSE.) .NEQV. (3 <= 5 .AND. 4 >= 2) .NOT. ([.FALSE. .AND. .FALSE.]) .NEQV. (3 <= 5 .AND. 4 >= 2) .NOT. (.FALSE.) .NEQV. (3 <= 5 .AND. 4 >= 2) [.NOT. .FALSE.] .NEQV. (3 <= 5 .AND. 4 >= 2) .TRUE. .NEQV. (3 <= 5 .AND. 4 >= 2) .TRUE. .NEQV. ([3 <= 5] .AND. 4 >= 2) .TRUE. .NEQV. (.TRUE. .AND. 4 >= 2) .TRUE. .NEQV. (.TRUE. .AND. [4 >= 2]) .TRUE. .NEQV. (.TRUE. .AND. .TRUE.) .TRUE. .NEQV. ([.TRUE. .AND. .TRUE.]) .TRUE. .NEQV. (.TRUE.) .TRUE. .NEQV. .TRUE. .FALSE.
Assignments
The result of a logical expression can be assigned into a LOGICAL variable. Note that only logical values can be put into LOGICAL variables. The follow assignments save the results of the examples into LOGICAL variables: LOGICAL :: Result1, Result2, Result3, Result4
= = = =
.NOT. Something .AND. Another .NOT. a .OR. .NOT. b .AND. c (n**2 + 1 > 10) .AND. .NOT. (n < 3) .NOT. (m > n .AND. x < y) .NEQV. (m <= n .AND. x >= y)
Thus, Result1, Result2, Result3 and Results receive .FALSE., .FALSE., .TRUE. and .FALSE., respectively.
IF-THEN-ELSE-END IF
IF-THEN-ELSE-END IF
The most general form of the IF-THEN-ELSE-END IF statement is the following: IF (logical-expression) THEN statements-1 ELSE statements-2 END IF where statements-1 and statements-2 are sequences of executable statements, and logical-expression is a logical expression. The execution of this IF-THEN-ELSE-END IF statement goes as follows:
q q q q
the logical-expression is evaluated, yielding a logical value if the result is .TRUE., the statements in statements-1 are executed if the result is .FALSE., the statements in statements-2 are executed after finish executing statements in statements-1 or statements-2, the statement following END IF is executed.
Examples
q
The following code first reads in an integer into INTEGER variable Number. Then, if Number can be divided evenly by 2 (i.e., Number is a multiple of 2), the WRITE(*,*) between IF and ELSE is executed and shows that the number is even; otherwise, the WRITE(*,*) between ELSE and END IF is executed and shows that the number is odd. Function MOD(x,y) computes the remainder of x divided by y. This is the the remainder (or modulo) function INTEGER :: Number READ(*,*) Number IF (MOD(Number, 2) == 0) THEN WRITE(*,*) Number, ' is even' ELSE WRITE(*,*) Number, ' is odd' END IF
The following program segment computes the absolute value of X and saves the result into variable Absolute_X. Recall that the absolute value of x is x if x is non-negative; otherwise, the absolute value is -x. For example, the absolute value of 5 is 5 and the absolute value of -4 is 4=-(-4). Also note that the WRITE(*,*) statement has been intentionally broken into two lines with the continuation line symbol &. REAL :: X, Absolute_X
IF-THEN-ELSE-END IF
Absolute_X = X ELSE Absolute_X = -X END IF WRITE(*,*) 'The absolute value of ', x, & ' is ', Absolute_X
q
The following program segment reads in two integer values into a and b and finds the smaller one into Smaller. Note that the WRITE(*,*) has also been broken into two lines. INTEGER :: a, b, Smaller
READ(*,*) a, b IF (a <= b) THEN Smaller = a ELSE Smaller = b END IF Write(*,*) 'The smaller of ', a, ' and ', & b, ' is ', Smaller
A Useful Tip
You may find the following way of organizing IF-THEN-ELSE-END IF very useful, especially when your program logic is reasonably complex. Draw a rectangular box and a vertical line dividing the box into two parts. Then, write down the logical expression in the left part and draw a horizontal line dividing the right parts into two smaller ones. The upper rectangle is filled with what you want to do when the logical expression is .TRUE., while the lower rectangle is filled with what you want to do when the logical expression is .FALSE.: what you want to do when the logical expression is .TRUE. what you want to do when the logical expression is . FALSE.
logicalexpression
For example, the third example above has the following description: a is the smaller number b is the smaller number
a <= b
Although this is an easy example, you will sense its power when you will be dealing with more complex problems.
IF-THEN-END IF
IF-THEN-END IF
The IF-THEN-END IF form is a simplification of the general IF-THEN-ELSE-END IF form with the ELSE part omitted: IF (logical-expression) THEN statements END IF where statements is a sequence of executable statements, and logical-expression is a logical expression. The execution of this IF-THEN-ELSE-END IF statement goes as follows:
q q
the logical-expression is evaluated, yielding a logical value if the result is .TRUE., the statements in statements are executed, followed by the statement following the IFTHEN-END IF statement. if the result is .FALSE., the statement following the IF-THEN-END IF is executed. In other words, if logicalexpression is .FALSE., there is no action taken.
Examples
q
The following program segment computes the absolute value of X and saves the result into variable Absolute_X. Recall that the absolute value of x is x if x is non-negative; otherwise, the absolute value is -x. For example, the absolute value of 5 is 5 and the absolute value of -4 is 4=-(-4). Also note that the WRITE(*,*) statement has been intentionally broken into two lines with the continuation line symbol &. The trick is that the value of X is first saved to Absolute_X whose value is changed later only if the value of X is less than zero. REAL :: X, Absolute_X
X = ..... Absolute_X = X IF (X < 0.0) THEN Absolute_X = -X END IF WRITE(*,*) 'The absolute value of ', x, & ' is ', Absolute_X
q
The following program segment reads in two integer values into a and b and finds the smaller one into Smaller. Note that the WRITE(*,*) has also been broken into two lines. This uses the same trick discussed in the previous example. INTEGER :: a, b, Smaller
READ(*,*) a, b Smaller = a
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/if-then.html (1 of 2)8/5/2006 8:04:42 PM
IF-THEN-END IF
IF (a > b) THEN Smaller = b END IF Write(*,*) 'The smaller of ', a, ' and ', & b, ' is ', Smaller
q
In many cases, it is required to do something when certain condition is satisfied; otherwise, do nothing. This is exactly what we need the form of IF-THEN-END IF. In the following, an INTEGER variable Counter is used for counting something. When its value is a multiple of 10, a blank line is displayed. INTEGER :: Counter IF (MOD(Counter, 10) == 0) THEN WRITE(*,*) END IF
A Useful Tip
The box trick can also be used with this IF-THEN-END IF form. Since there is no ELSE, you can leave the lower part empty like the following: what you want to do when the logical expression is . TRUE. nothing is here!!!
logicalexpression
Logical IF
Logical IF
The logical IF is the simplest form. It has the following form: IF (logical-expression) one-statement
where one-statement is a executable statement which is not another IF, and logical-expression is a logical expression. The execution of this logical IF statement goes as follows:
q q
the logical-expression is evaluated, yielding a logical value if the result is .TRUE., the statement in one-statement is executed, followed by the statement following the logical IF statement. if the result is .FALSE., the statement following the logical IF is executed. In other words, when logical-expression is .FALSE., there is no action taken.
Note that this logical IF does have its use although it looks not so powerful comparing with IF-THEN-ELSE-END IF and IF-THEN-END IF.
Examples
q
The following program segment computes the absolute value of X and saves the result into variable Absolute_X. Recall that the absolute value of x is x if x is non-negative; otherwise, the absolute value is -x. For example, the absolute value of 5 is 5 and the absolute value of -4 is 4=-(-4). Also note that the WRITE(*,*) statement has been intentionally broken into two lines with the continuation line symbol &. The trick is that the value of X is first saved to Absolute_X whose value is changed later only if the value of X is less than zero. REAL :: X, Absolute_X
X = ..... Absolute_X = X IF (X < 0.0) Absolute_X = -X WRITE(*,*) 'The absolute value of ', x, & ' is ', Absolute_X
q
The following program segment reads in two integer values into a and b and finds the smaller one into Smaller. Note that the WRITE(*,*) has also been broken into two lines. This uses the same trick discussed in the previous example. INTEGER :: a, b, Smaller
READ(*,*) a, b Smaller = a IF (a > b) Smaller = b Write(*,*) 'The smaller of ', a, ' and ', & b, ' is ', Smaller
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/if.html (1 of 2)8/5/2006 8:04:44 PM
Logical IF
In many cases, it is required to do something when certain condition is satisfied; otherwise, do nothing. This is exactly what we need the form of IF-THEN-END IF. In the following, an INTEGER variable Counter is used for counting something. When its value is a multiple of 10, a blank line is displayed. INTEGER :: Counter IF (MOD(Counter, 10) == 0) WRITE(*,*)
The following is wrong since the one-statement if a logical IF can not be another IF statement. INTEGER :: a, b, c IF (a < b) IF (b < c) WRITE(*,*) a, b, c
From the above examples, one can easily see that if the THEN part has exactly one statement and there is no ELSE, the logical IF statement can save some space making a program a little shorter. But, my advice is that don't use it whenever it is possible.
if b*b-4*a*c is non-negative, the roots of the equation can be solved with the following formulae:
Write a program to read in the coefficients a, b and c, and compute and display the roots. If the discriminant b*b - 4*a*c is negative, the equation has complex root. Thus, this program should solve the equation if the discriminant is non-negative and show a message otherwise.
Solution
! --------------------------------------------------! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0 ! Now, we are able to detect complex roots. ! --------------------------------------------------PROGRAM QuadraticEquation IMPLICIT NONE REAL REAL REAL ! :: a, b, c :: d :: root1, root2
read in the coefficients a, b and c READ(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) a, 'a 'b 'c b, c = ', a = ', b = ', c
compute the square root of discriminant d d = b*b - 4.0*a*c IF (d >= 0.0) THEN ! is it solvable? d = SQRT(d) root1 = (-b + d)/(2.0*a) ! first root root2 = (-b - d)/(2.0*a) ! second root WRITE(*,*) 'Roots are ', root1, ' and ', root2 ELSE ! complex roots WRITE(*,*) 'There is no real roots!' WRITE(*,*) 'Discriminant = ', d END IF
END PROGRAM
QuadraticEquation
If the input to the program consists of 1.0, 5.0 and 2.0, we have the following output. Since the discriminant is b*b 4.0*a*c = 5.0*5.0 - 4.0*1.0*2.0 = 17.0 > 0.0, the THEN part is executed and the real roots are -0.438447237 and 4.561553. 1.0 5.0 2.0
If the input to the program consists of 1.0, 2.0 and 5.0, we have the following output. Since the discriminant is b*b 4.0*a*c = 2.0*2.0 - 4.0*1.0*5.0 = -16.0 < 0.0, the ELSE part is executed and a message of no real roots is displayed followed the value of the discriminant. 1.0 2.0 5.0
Discussion
Here is the box trick of this program. Note that information in different parts of the box do not have to be very precise. As
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/quad-2.html (2 of 3)8/5/2006 8:04:48 PM
long as it can tell what to do, it would be sufficient. computes the real roots there is no real roots
Solution
! ! ! ! ! ! ! ! ! ------------------------------------------------------------Two examination papers are written at the end of the course. The final mark is either the average of the two papers, or the average of the two papers and the class record mark (all weighted equally), whichever is the higher. The program should reads in the class record mark and the marks of the papers, computes the average, and shows PASS (>= 50%) or FAIL (< 50%). -------------------------------------------------------------
PROGRAM FinalMark IMPLICIT NONE REAL REAL REAL :: Mark1, Mark2 :: Final :: ClassRecordMark ! the marks of the papers ! the final marks ! the class record mark ! the pass level
Final = (Mark1 + Mark2) / 2.0 IF (Final <= ClassRecordMark) THEN Final = (Mark1 + Mark2 + ClassRecordMark) / 3.0 END IF WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) 'Class Record Mark : ', ClassRecordMark 'Mark 1 : ', Mark1 'Mark 2 : ', Mark2 'Final Mark : ', Final
: PASS'
'Pass Status
: FAIL'
FinalMark
If the input to class record mark, the mark of the first paper, and the mark of the second paper are 40.0, 60.0 and 43.0, the average is (60.0 + 43.0)/2 = 51.5, which is larger than the class record mark (40.0). Therefore, this student has a final mark 51.5 and receives a PASS status. 40.0 60.0 43.0
Class Record Mark : 40. Mark 1 : 60. Mark 2 : 43. Final Mark : 51.5 Pass Status : PASS
q
If the input to class record mark, the mark of the first paper, and the mark of the second paper are 60.0, 45.0 and 43.0, then the average is (45.0 + 43.0)/2 = 44.0, which is less than the class record mark (60.0). Therefore, this student's new mark is the average of his marks and the class record mark, (60.0 + 45.0 + 43.0)/3.0 = 49.33333. Since this new mark is less than 50.0, this student receives a FAIL status. 60.0 45.0 43.0
Class Record Mark : 60. Mark 1 : 45. Mark 2 : 43. Final Mark : 49.3333321 Pass Status : FAIL
Discussion
q q q
q q
The READ statement reads in values for ClassRecordMark, Mark1 and Mark2. The average of papers is computed and stored in Final If this final mark is less than or equal to the class record mark, a new final mark is computed as the average of the two marks and the class record mark. Here, the IF-THEN-END form is used. You can use the logical IF form; but, this line could be too long. As mentioned earlier, the IF-THEN-END IF is preferred. The four WRITE(*,*) statements display the input and the computed final mark. Finally, the IF-THEN-ELSE-END IF determines if the final mark is a pass or a fail.
Write a program to read in the coefficients a, b and c, and compute the area of the triangle. However, not any three numbers can make a triangle. There are two conditions. First, all side lengths must be positive:
and second the sum of any two side lengths must be greater than the third side length:
In the program, these two conditions must be checked before computing the triangle area; otherwise, square root computation will be in trouble.
Solution
! -----------------------------------------------------! Compute the area of a triangle using Heron's formula ! -----------------------------------------------------PROGRAM HeronFormula IMPLICIT NONE REAL REAL REAL :: a, b, c :: s :: Area ! three sides ! half of perimeter ! triangle area
LOGICAL READ(*,*)
Cond_1 = (a > 0.) .AND. (b > 0.) .AND. (c > 0.0) Cond_2 = (a+b > c) .AND. (a+c > b) .AND. (b+c > a) IF (Cond_1 .AND. Cond_2) THEN s = (a + b + c) / 2.0 Area = SQRT(s*(s-a)*(s-b)*(s-c)) WRITE(*,*) "Triangle area = ", Area ELSE WRITE(*,*) "ERROR: this is not a triangle!" END IF END PROGRAM HeronFormula
If the input to the program consists of 3.0, 5.0 and 7.0, we have the following output. Since the value of all input are positive and the sum of any two is larger than the third (i.e., 3.0+5.0 > 7.0, 3.0+7.0+5.0 and 5.0+7.0>3.0), both conditions hold and the program can compute the area of the triangle. The area is 6.49519062. 3.0 5.0 7.0
If the input to the program consists of 3.0, 4.0 and 7.0, we have the following output. Although all input values are positive, this is not a triangle since the sum of the first side (3.0) and the second (4.0) is not grater than the third (8.0). The program generates an error message. 3.0 4.0 8.0
If the input to the program consists of -1.0, 3.0 and 5.0, we have the following output. Since not all input values are positive, this is not a triangle. -1.0 3.0 5.0
Discussion
q q q q
q q
This program uses two LOGICAL variables, Cond_1 and Cond_2 to store the results of the two conditions. The conditions are checked with the first two assignments. Since all side lengths must be greater than zero, operator .AND. are used to connect a > 0.0, b > 0.0 and c > 0.0. Since the sum of any two side lengths must be greater than the third side length, all three comparisons must be . TRUE. and operator .AND. is used. Since both conditions must be true in order to have a triangle, .AND. is also used in the IF-THEN-ELSE-END IF statement. If both conditions are .TRUE., the THEN part is executed, where the value of s and the area is computed and displayed. If one or both conditions is .FALSE., the input is not a triangle and an error message is displayed. You can pull all six comparisons into a single logical expression. But, this expression could be too long to be fit into a single line. While continuation line can be used, it may not be readable. So, I prefer to have separate lines.
Here is the box trick of this program. computes s and its area displays an error message
Nested IF-THEN-ELSE-END IF
Nested IF-THEN-ELSE-END IF
The THEN part and the ELSE part, if any, can contain one or more IF-THEN-ELSE-END IF statement in one of the three forms. That is, when you feel it is necessary, you can use as many IF-THEN-ELSE-END IF statements in the THEN part and the ELSE part as you want. However, please note that any such IF-THEN-ELSE-END IF must be fully contained in the THEN part or the ELSE part. If you follow the box trick, this requirement is automatically satisfied. The following is an example: IF (logical-expression) THEN statements IF (logical-expression) THEN statements ELSE statements END IF statements ELSE statements IF (logical-expression) THEN statements END IF statements END IF
Examples
q
Suppose we need a program segment to read a number x and display its sign. More precisely, if x is positive, a + is displayed; if x is negative, a - is displayed; otherwise, a 0 is displayed. With an IF-THEN-ELSE-END IF statement, we have a two-way decision (i.e., true or false). What we need is a tree-way decision and some trick is required. In this case, the box trick can be very helpful. Let us start testing if x is positive. What we get is the following: display + x> 0 one down (i.e., +) two to go (i.e., - and 0) In the lower part, no decision can been reached. What we want to know is finding out is x is zero or negative (x cannot be positive here since it has been ruled out in the upper part). To determine whether a - or a 0 should be displayed, one more decision is required: display -
x<
Nested IF-THEN-ELSE-END IF
display 0)
Since this is the work for the lower rectangle, let us put it there yielding the following: display + x> 0 x< 0 display display 0
Converting to a IF-THEN-ELSE-END IF construct is easy since the above box is almost identical to that. So, here is our answer: IF (x > 0) THEN WRITE(*,*) '+' ELSE IF (x < 0) THEN WRITE(*,*) '-' ELSE WRITE(*,*) '0' END IF END IF
q
Given a x, we want to display the value of -x if x < 0, the value of x*x if x is in the range of 0 and 1 inclusive, and the value of 2*x if x is greater than 1. Obviously, this problem cannot be solved with a two-way IF and the box trick becomes useful. Let us start with x<0. display -x here we have x >= 0
x< 0
For the x >= 0 part, x may be in the range of 0 and 1; if not, x must be greater than 1 since x cannot be less than 0. Therefore, we have the following box for the case of x >= 0: x <= 1 x is in the range of 0 and 1. display x*x here we have x > 1. display 2*x
Inserting this box into the previous one yields the following final result: display -x x< 0 x <= 1 display x*x
Nested IF-THEN-ELSE-END IF
display 2*x Converting to using IF, we have the following: IF (x < 0) THEN WRITE(*,*) -x ELSE IF (x <= 1) THEN WRITE(*,*) x*x ELSE WRITE(*,*) 2*x END IF END IF
q
Given three numbers a, b and c, we want to find out the smallest one. There are many solutions to this problem; but, we shall use the box trick again. Let us pick two numbers, say a and b. Thus, we get the following: a has the potential to be the smallest since b <= a, b has the potential to be the smallest
a< b
Now we know a possible smallest number. To find the real smallest one, this "possible" number must be compared against c. If the possible one is a (the upper part), we need to do the following: a is the smallest a< c since c <= a and b <= a, c is the smallest Let us turn to the lower part, where b has the potential to be the smallest. Comparing with c yields: b is the smallest b< c since c <= b and b <= a, c is the smallest Inserting the above two boxes into the first one yields the following complete solution: a< c a< b b< c the smallest is a the smallest is c the smallest is b the smallest is c
Nested IF-THEN-ELSE-END IF
Converting to the IF version, we have IF (a < b) THEN IF (a < c) THEN Result = a ELSE Result = c END IF ELSE IF (b < c) THEN Result = b ELSE Result = c END IF END IF WRITE(*,*) 'The smallest is ', Result The above code segment uses variable Result to hold the smallest value.
IF-THEN-ELSE IF-END IF
IF-THEN-ELSE IF-END IF
The Nested IF-THEN-ELSE-END IF statement could produce a deeply nested IF statement which is difficult to read. There is a short hand to overcome this problem. It is the IF-THEN-ELSE IF-END-IF version. Its syntax is shown below: IF (logical-expression-1) THEN statements-1 ELSE IF (logical-expression-2) THEN statements-2 ELSE IF (logical-expression-3) THEN statement-3 ELSE IF (.....) THEN ........... ELSE statements-ELSE END IF Fortran evaluates logical-expression-1 and if the result is .TRUE., statements-1 is executed followed by the statement after END IF. If logical-expression-1 is .FALSE., Fortran evaluates logical-expression-2 and executes statements-2 and so on. In general, if logical-expression-n is .TRUE., statements-n is executed followed by the statement after END IF; otherwise, Fortran continues to evaluate the next logical expression. If all logical expressions are .FALSE. and if ELSE is there, Fortran executes the statements-ELSE; otherwise, Fortran executes the statement after the END IF. Note that the statements in the THEN section, ELSE IF section, and ELSE section can be another IF statement.
Examples
q
Suppose we need a program segment to read a number x and display its sign. More precisely, if x is positive, a + is displayed; if x is negative, a - is displayed; otherwise, a 0 is displayed. Here is a possible solution using IF-THENELSE IF-END IF: IF (x > 0) THEN WRITE(*,*) '+' ELSE IF (x == 0) THEN WRITE(*,*) '0' ELSE WRITE(*,*) '-' END IF
Given a x, we want to display the value of -x if x < 0, the value of x*x if x is in the range of 0 and 1 inclusive, and the value of 2*x if x is greater than 1. The following is a possible solution:
IF-THEN-ELSE IF-END IF
IF (x < 0) THEN WRITE(*,*) -x ELSE IF (x <= 1) THEN WRITE(*,*) x*x ELSE WRITE(*,*) 2*x END IF
q
Consider the following code segment: INTEGER :: x CHARACTER(LEN=1) :: Grade IF (x < 50) THEN Grade = 'F' ELSE IF (x < 60) THEN Grade = 'D' ELSE IF (x < 70) THEN Grade = 'C' ELSE IF (x < 80) THEN Grade = 'B' ELSE Grade = 'A' END IF First, if xis less than 50, 'F'is assigned to Grade. If xis greater than or equal to 50, the execution continue with the first ELSE IFwhere x < 60is tested. If it is .TRUE., 'D'is assigned to Grade. Note that one can reach the test of x < 60simply because the test x < 50is .FALSE.. Therefore, when reaches x < 60, we are sure that x >= 50must hold and as a result, Gradereceives 'D'if xis greater than or equal to 50 and is less than 60. By the same token, we know that if x is greater than or equal to 60 and is less than 70, Grade receives 'C'. If x is greater than or equal to 70 and is less than 80, Grade receives 'B'. Finally, if x is greater than or equal to 80, Grade receives 'A'.
The first and second examples show that IF-THEN-ELSE IF-END IF can save some space and at the same time make a program more readable. Compare these two solutions with those using nest IF. Note also that not all nested IF can be converted to the IF-THEN-ELSE IF-ELSE-END-IF form. For example, the example of determining the smallest of three numbers cannot be converted immediately. In general, if all tests (i.e., logical expressions) are mutually exclusive, then the chance to have a successful conversion is high. Otherwise, rewriting some parts or combining logical expression can be helpful. Here is one more example: Let us reconsider the problem of finding the smallest of three given numbers. We know that if a is the smallest, then it must be smaller than the other two. Moreover, the condition for a number being the smallest is mutually exclusive. Thus, we have a successful conversion as follows: IF (a < b .AND. a < c) THEN Result = a ELSE IF (b < a .AND. b < c) THEN
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/else-if.html (2 of 3)8/5/2006 8:04:59 PM
IF-THEN-ELSE IF-END IF
if b*b-4*a*c is non-negative, the roots of the equation can be solved with the following formulae:
Write a program to read in the coefficients a, b and c, and solve the equation. Note that a quadratic equation has repeated root if b*b-4.0*a*c is equal to zero. This program should distinguish repeated roots from distinct roots.
Solution
! --------------------------------------------------! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0 ! Now, we are able to detect complex roots and ! repeated roots. ! --------------------------------------------------PROGRAM QuadraticEquation IMPLICIT NONE REAL REAL REAL ! :: a, b, c :: d :: root1, root2
read in the coefficients a, b and c READ(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) a, 'a 'b 'c b, c = ', a = ', b = ', c
compute the discriminant d d = b*b - 4.0*a*c IF (d > 0.0) THEN ! distinct roots? d = SQRT(d) root1 = (-b + d)/(2.0*a) ! first root root2 = (-b - d)/(2.0*a) ! second root WRITE(*,*) 'Roots are ', root1, ' and ', root2 ELSE IF (d == 0.0) THEN ! repeated roots? WRITE(*,*) 'The repeated root is ', -b/(2.0*a) ELSE ! complex roots WRITE(*,*) 'There is no real roots!' WRITE(*,*) 'Discriminant = ', d END IF END IF
END PROGRAM
QuadraticEquation
If the input to the program consists of 1.0, 5.0 and 2.0, we have the following output. Since the discriminant is b*b 4.0*a*c = 5.0*5.0 - 4.0*1.0*2.0 = 17.0 > 0.0, the THEN part is executed and the real roots are -0.438447237 and 4.561553. 1.0 5.0 2.0
If the input to the program consists of 1.0, -10.0 and 25.0, we have the following output. Since the discriminant is b*b - 4.0*a*c = (-10.0)*(-10.0) - 4.0*1.0*25.0 = 0.0, the ELSE part is executed. Since there is a nested IF-THENELSE-END IF in the ELSE, d = 0.0 is tested and therefore yields a repeated root 5. 1.0 -10.0 25.0
If the input to the program consists of 1.0, 2.0 and 5.0, we have the following output. Since the discriminant is b*b 4.0*a*c = 2.0*2.0 - 4.0*1.0*5.0 = -16.0 < 0.0, the ELSE part is executed. Since d < 0.0, the ELSE part of the inner
IF-THEN-ELSE-END IF is executed and a message of no real roots is displayed followed by the value of the discriminant. 1.0 2.0 5.0
Discussion
Here is the box trick of this program. computes the real roots repeated root or no real root
The lower part is not complete yet since we do not know if the equation has a repeated root. Therefore, one more test is required: computes the repeated root no real root
Inserting this back to the original yields the following final result: computes the real roots b*b - 4.0*a*c > 0.0 b*b - 4.0*a*c = 0.0 compute the repeated root no real root
The following is an equivalent program that uses ELSE-IF construct rather than nested IF: ! --------------------------------------------------! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0 ! Now, we are able to detect complex roots and
! repeated roots. ! --------------------------------------------------PROGRAM QuadraticEquation IMPLICIT NONE REAL REAL REAL ! :: a, b, c :: d :: root1, root2
read in the coefficients a, b and c READ(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) a, 'a 'b 'c b, c = ', a = ', b = ', c
compute the discriminant d d = b*b - 4.0*a*c IF (d > 0.0) THEN ! distinct roots? d = SQRT(d) root1 = (-b + d)/(2.0*a) ! first root root2 = (-b - d)/(2.0*a) ! second root WRITE(*,*) 'Roots are ', root1, ' and ', root2 ELSE IF (d == 0.0) THEN ! repeated roots? WRITE(*,*) 'The repeated root is ', -b/(2.0*a) ELSE ! complex roots WRITE(*,*) 'There is no real roots!' WRITE(*,*) 'Discriminant = ', d END IF
END PROGRAM
QuadraticEquation
Click here to download this program. Its logic is shown below using the box trick. > computes the real roots b*b - 4.0*a*c ? 0.0 = computes the repeated root
if b*b-4*a*c is non-negative, the roots of the equation can be solved with the following formulae:
Write a program to read in the coefficients a, b and c, and solve the equation. Note that a quadratic equation has repeated root if b*b-4.0*a*c is equal to zero. However, if a is zero, the equation becomes a linear one whose only solution is -c/b if b is not zero. Otherwise, if b is zero, two cases are possible. First, if c is also zero, any number can be a solution because all three coefficients are zero. Otherwise, the equation c = 0 cannot have any solution. This program should handle all cases.
Solution
! --------------------------------------------------! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0 ! Now, we are able to detect the following: ! (1) unsolvable equation ! (2) linear equation ! (3) quadratic equation ! (a) distinct real roots ! (b) repeated root ! (c) no real roots ! --------------------------------------------------PROGRAM QuadraticEquation IMPLICIT NONE REAL :: a, b, c
REAL REAL !
:: d :: root1, root2
read in the coefficients a, b and c READ(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) a, 'a 'b 'c b, c = ', a = ', b = ', c
IF (a == 0.0) THEN ! could be a linear equation IF (b == 0.0) THEN ! the input becomes c = 0 IF (c == 0.0) THEN ! all numbers are roots WRITE(*,*) 'All numbers are roots' ELSE ! unsolvable WRITE(*,*) 'Unsolvable equation' END IF ELSE ! linear equation WRITE(*,*) 'This is linear equation, root = ', -c/b END IF ELSE ! ok, we have a quadratic equation d = b*b - 4.0*a*c IF (d > 0.0) THEN ! distinct roots? d = SQRT(d) root1 = (-b + d)/(2.0*a) ! first root root2 = (-b - d)/(2.0*a) ! second root WRITE(*,*) 'Roots are ', root1, ' and ', root2 ELSE IF (d == 0.0) THEN ! repeated roots? WRITE(*,*) 'The repeated root is ', -b/(2.0*a) ELSE ! complex roots WRITE(*,*) 'There is no real roots!' WRITE(*,*) 'Discriminant = ', d END IF END IF END PROGRAM QuadraticEquation
If the input to the program consists of 0.0, 1.0 and 5.0, we have the following output. Since a is zero, this could be a linear equation. Since b=1.0, it is a linear equation 1.0*x + 5.0 = 0.0 with the only root -5.0/2.0=-5.0. 0.0 1.0 5.0
If the input to the program consists of 0.0, 0.0 and 0.0, we have the following output. Since all coefficients are zero, any number is a root. 0.0 0.0 0.0
If the input to the program consists of 0.0, 0.0 and 4.0, we have the following output. Since the equation becomes 4.0 = 0.0, which is impossible. Therefore, this is not a solvable equation. 0.0 0.0 4.0
Discussion
Here is the box trick of this program. It is more complex than all previous versions of quadratic equation solvers. Let us start with linear equations. it could be a linear equation a quadratic equation
a= 0
Since we have learned to do the quadratic part, we shall do the linear equation part first. To be a linear equation, b cannot be zero and this has to be addressed in the upper rectangle: need to know if c is zero the equation is linear b*x +c=0
a= 0
b= 0
a quadratic equation If c is zero, then every number is a root and we have: every number is a root this equation is not solvable
a= 0
b= 0
c= 0
To complete the bottom rectangle, let us take the box from previous example. The final result is: every number is a root this equation is not solvable computes the real roots computes the repeated root no real root
c= 0
Solution
! ! ! ! ------------------------------------------------------This program reads in three INTEGERs and displays them in ascending order. -------------------------------------------------------
PROGRAM Order IMPLICIT NONE INTEGER READ(*,*) :: a, b, c a, b, c ! a < b here ! a < c ! b < c c ! b ! a >= c : c <= a < b c <= b : a < c <= b
IF (a < b) THEN IF (a < c) THEN IF (b < c) THEN WRITE(*,*) a, b, ELSE WRITE(*,*) a, c, END IF ELSE WRITE(*,*) c, a, b END IF ELSE IF (b < c) THEN IF (a < c) THEN WRITE(*,*) b, a, ELSE WRITE(*,*) b, c, END IF ELSE WRITE(*,*) c, b, a END IF END IF END PROGRAM Order
! b <= a here ! b < c : b the smallest ! a < c : b <= a < c c ! a ! c <= b : c <= b <= a a >= c : b < c <= a
Discussion
This is a good example for using the box trick. The main idea is that if we know the smallest number, then one comparison between the remaining two would give the second smallest and the largest number. Finding the smallest of three numbers has been discussed in nested IF. So, let us start with a: a< b a may be the smallest b may be the smallest
For the upper rectangle, we need to know if a is less than c, while for the lower rectangle we need to know if b is less than c: a is the smallest, relation between b and c unknown c <= a < b here, sorted!!!
a< c a< b
b is the smallest, relation between a and c b < unknown c c <= b <= a here, sorted!!!
For the top rectangle, we need one more comparison b < c and for the rectangle on the third row we need a < c. The following is our final result: b < a < b < c here, sorted!!! c a < c <= b here, sorted c <= a < b here, sorted!!! a< b b< c b <= a < c here, a < sorted!!! c b < c <= a here, sorted!!! c <= b <= a here, sorted!!!
a< c
The above can be simplified a little if you use LOGICAL operators as discussed in nested IF. Here is the box diagram: a < b < c here a < b <= c here
b< c
b < a < c here a < c b < c <= a here c < a < b here c < b <= a here
Converting this diagram to IF-THEN-ELSE IF we have the following: ! ! ! ! ------------------------------------------------------This program reads in three INTEGERs and displays them in ascending order. -------------------------------------------------------
IF (a <= b .AND. a <= c) THEN ! a the smallest IF (b <= c) THEN ! a <= b <= c WRITE(*,*) a, b, c ELSE ! a <= c <= b WRITE(*,*) a, c, b END IF ELSE IF (b <= a .AND. b <= c) THEN ! b the smallest IF (a <= c) THEN ! b <= a <= c WRITE(*,*) b, a, c ELSE ! b <= c <= a WRITE(*,*) b, c, a END IF ELSE ! c the smallest IF (a <= b) THEN ! c <= a <= b WRITE(*,*) c, a, b ELSE ! c <= b <= a WRITE(*,*) c, b, a END IF END IF END PROGRAM Order
q q
The first form has only one value The second form means all values in the range of value-1 and value-2. In this form, value-1 must be less than value2. The third form means all values that are greater than or equal to value-1 The fourth form means all values that are less than or equal to value-2
The selector expression is evaluated If the result is in label-list-i, then the sequence of statements in statements-i are executed, followed by the statement following END SELECT
If the result is not in any one of the label lists, there are two possibilities: r if CASE DEFAULT is there, then the sequence of statements in statements-DEFAULT are executed, followed by the statement following END SELECT r if there is no CASE DEFAULT is not there, the statement following END SELECT is executed.
The constants listed in label lists must be unique CASE DEFAULT is optional. But with a CASE DEFAULT, you are guaranteed that whatever the selector value, one of the labels will be used. I strongly suggest to add a CASE DEFAULT in every SELECT CASE statement. The place for CASE DEFAULT can be anywhere within a SELECT CASE statement; however, put it at the end would be more natural.
Examples
q
The following uses Class to execute a selection. If Class is 1, Freshman is displayed; if Class is 2, Sophomore is displayed; if Class is 3, Junior is displayed; if Class is 4, Senior is displayed; and if Class is none of the above, Hmmmm, I don't know is displayed. After displaying one of the above, Done is displayed. INTEGER :: Class SELECT CASE (Class) CASE (1) WRITE(*,*) 'Freshman' CASE (2) WRITE(*,*) 'Sophomore' CASE (3) WRITE(*,*) 'Junior' CASE (4) WRITE(*,*) 'Senior' CASE DEFAULT WRITE(*,*) "Hmmmm, I don't know" END SELECT WRITE(*,*) 'Done'
In the following, the value of CHARACTER variable Title is used as a selector. If its value is "DrMD" (resp., "PhD", "MS" and "BS"), then INTEGER variables DrMD (resp., PhD, MS and BS) is increased by 1. Otherwise, Others is increased. CHARACTER(LEN=4) :: Title INTEGER :: DrMD = 0, PhD = 0, MS = 0, BS = 0, Others = 0 SELECT CASE (Title) CASE ("DrMD") DrMD = DrMD + 1 CASE ("PhD") PhD = PhD + 1 CASE ("MS")
The follow example does not use CASE DEFAULT since the label lists have already covered all possibilities. If the value of Number is less than or equal to -1 (:-1), -1 is stored into Sign. If the value of Number is zero, 0 is stored into Sign. If the value of Number is greater than or equal to 1, 1 is stored into Sign. INTEGER :: Number, Sign SELECT CASE (Number) CASE ( : -1) Sign = -1 CASE (0) Sign = 0 CASE (1 : ) Sign = 1 END SELECT WRITE(*,*) "Sign = ", Sign
If the value of c is one of the first ten letters (in lower case), 'One of the first ten letters' is displayed; if the value of c is one of l, m, n, o, p, u, v, w, x, y, 'One of l, m, n, o, p, u, v, w, x, y' is displayed; if the value of c is one of z, q, r, s, t, 'One of z, q, r, s, t' is displayed; and if the value of c is none of the above, 'Other characters, which may not be letters' is displayed. In the last case, the value of c could be one of these lower case letters not listed, an upper case letters, a digit, an operator, or any other character. So, if you only want to handle lower case letters, this program is incorrect. CHARACTER(LEN=1) :: c SELECT CASE (c) CASE ('a' : 'j') WRITE(*,*) 'One of the first ten letters' CASE ('l' : 'p', 'u' : 'y') WRITE(*,*) 'One of l, m, n, o, p, u, v, w, x, y' CASE ('z', 'q' : 't') WRITE(*,*) 'One of z, q, r, s, t' CASE DEFAULT WRITE(*,*) 'Other characters, which may not be letters' END SELECT
The following program uses the value of Number to determine the value of Range. INTEGER :: Number, Range SELECT CASE (Number) CASE ( : -10, 10 : ) Range = 1
CASE (-5:-3, 6:9) Range = 2 CASE (-2:2) Range = 3 CASE (3, 5) Range = 4 CASE (4) Range = 5 CASE DEFAULT Range = 6 END SELECT Here is the result: Number <= -10 -9, -8, -7, -6 -5, -4, -3 -2, -1, 0, 1, 2 3 4 5 6, 7, 8, 9 >= 10 Range 1 6 2 3 4 5 4 2 1 Why? CASE ( : -10, 10 : ) CASE DEFAULT CASE (-5:-3, 6:9) CASE (-2:2) CASE (3, 5) CASE (4) CASE (3, 5) CASE (-5:-3, 6:9) CASE ( : -10, 10 : )
Write a program to read three marks, compute its average, round the average and use it to determine the corresponding letter grade.
Solution
! ! ! ! ! ! ! ! ! ! ! ! ! ! ---------------------------------------------------------This program reads three marks, computes their average and determines the corresponding letter grade with the following table: A AB B BC C CD D F : : : : : : : : average >= 90 85 <= average 80 <= average 75 <= average 70 <= average 65 <= average 60 <= average average < 60
90 84 79 74 69 64
! ! ! ! !
where 'average' is the rounded average of the three marks. More precisely, if the average is 78.6, then it becomes 79 after rounding; or, if the average is 78.4, it becomes 78 after truncating. ----------------------------------------------------------
PROGRAM LetterGrade IMPLICIT NONE REAL REAL CHARACTER(LEN=2) :: Mark1, Mark2, Mark3 :: Average :: Grade
READ(*,*) Mark1, Mark2, Mark3 Average = (Mark1 + Mark2 + Mark3) / 3.0 SELECT CASE (NINT(Average)) CASE (:59) Grade = 'F ' CASE (60:64) Grade = 'D ' CASE (65:69) Grade = 'CD' CASE (70:74) Grade = 'C ' CASE (75:79) Grade = 'BC' CASE (80:84) Grade = 'B ' CASE (85:89) Grade = 'AB' CASE DEFAULT Grade = 'A ' END SELECT WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) END PROGRAM 'First Mark 'Second Mark 'Third Mark 'Average 'Letter Grade LetterGrade : : : : : ', ', ', ', ', ! round Average before use ! <= 59 -------------> F ! >= 60 and <= 64 ---> D ! >= 65 and <= 69 ---> CD ! >= 70 and <= 74 ---> C ! >= 75 and <= 79 ---> BC ! >= 80 and <= 84 ---> B ! >= 84 and <= 89 ---> AB ! >= 90 -------------> A
The following output is generated from input 97.0, 90.0 and 94.0. The average is 93.66666641. The result after rounding is 94 and hence the letter grade is an A.
97.0
90.0
The following output is generated from input 92.0, 85.0 and 83.0. The average is 86.6666641. The result after rounding is 87 and hence the letter grade is an AB. 92.0 85.0 83.0 : : : : : 92. 85. 83. 86.6666641 AB
The following output is generated from input 75.0, 60.0 and 45.0. The average is 60.0. The result after rounding is 60 and hence the letter grade is an D. 75.0 60.0 45.0 : : : : : 75. 60. 45. 60. D
Discussion
This is an easy example and only one place requires further explanation. The concept of rounding is converting a real number to its nearest integer. Therefore, after rounding, 4.5 and 4.4 become 5 and 4, respectively. Moreover, after rounding, -4.5 and -4.4 become -5 and -4, respectively. The Fortran intrinsic function for rounding is NINT(), which was discussed in Fortran intrinsic functions. In the program, REAL variable Average holds the average of the three input marks. To round the average value to be used in the SELECT CASE statement, NINT(Average) is used. Other parts are obvious.
Solution
! ! ! ! ! ! ! ! ! ! ! ! -----------------------------------------------------------This program reads in a single character and determines if it is a vowel, a consonant, a digit, one of the four arithmetic operators (+, -, * and /), a space, or something else. You can do it with IF-THEN-ELSE-END IF statement; but SELECT CASE statement provides a cleaner solution. For character input, you could use the quote characters like 'G' Or, just type the character. In this case, the first character you type will be read. ------------------------------------------------------------
SELECT CASE (Input) CASE ('A' : 'Z', 'a' : 'z') ! rule out letters WRITE(*,*) 'A letter is found : "', Input, '"' SELECT CASE (Input) ! a vowel ? CASE ('A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o','u') WRITE(*,*) 'It is a vowel' CASE DEFAULT ! it must be a consonant WRITE(*,*) 'It is a consonant' END SELECT CASE ('0' : '9') ! a digit WRITE(*,*) 'A digit is found : "', Input, '"' CASE ('+', '-', '*', '/') ! an operator WRITE(*,*) 'An operator is found : "', Input, '"' CASE (' ') ! space WRITE(*,*) 'A space is found : "', Input, '"'
CharacterTesting
If the input character is s, the program should report it is a consonant. A letter is found : "s" It is a consonant
If the input character is U, the program should report it is a vowel. A letter is found : "U" It is a vowel
If the input character is 8, the program should report it is a digit. A digit is found : "8"
If the input character is +, the program should report it is an operator. An operator is found : "+"
If the input character is a space, the program should report it is a space. A space is found : " "
If the input character is none of the above, say &, the program should report it is something else. Something else found : "&"
Discussion
To be a vowel or a consonant, the input character must be a lower or upper case letter. So, the first CASE of the outer SELECT CASE singles out all letters. Within the first CASE, another SELECT CASE is used to separate vowels from consonants. Since a letter is either a vowel or a consonant, we use the shorter list (i.e., vowels) in the CASE label and let CASE DEFAULT deal with the longer list of consonants.
Repetitive Execution
Repetitive Execution
Select the topics you wish to review:
Repetitive Execution Counting DO-Loop Programming Examples: Counting Positive and Negative Input Values Computing Arithmetic, Geometric and Harmonic Means Computing Factorial General DO-Loop with EXIT Programming Examples: Determining the Minimum and Maximum of Input Data Computing the Square Root of a Positive Number Computing EXP(x) Computing the Greatest Common Divisor of Two Positive Integers Checking If a Positive Integer Is a Prime Number Nested DO-Loop Programming Examples: Computing Classes Averages Computing a Set of Values of EXP(x) Armstrong Numbers Finding All Primes in the Range of 2 and N Finding all Prime factors of a Positive Integer Handling End of File: the READ Statement Revisited Computing Arithmetic, Geometric and Harmonic Means: Revisited The DO-CYCLE Construct and a Programming Example (Optional) Download my course overheads
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/loop.html8/5/2006 8:05:43 PM
Counting DO-Loop
Counting DO-Loop
There are two forms of loops, the counting loop and the general loop. The syntax of the counting loop is the following: DO control-var = initial-value, final-value, [step-size] statements END DO where control-var is an INTEGER variable, initial-value and final-value are two INTEGER expressions, and step-size is also an INTEGER expression whose value cannot be zero. Note that step-size is optional. If it is omitted, the default value is 1. statements is a sequence of statements and is usually referred to as the body of the DO-loop. You can use any executable statement within a DO-loop, including IF-THEN-ELSE-END IF and even another DO-loop. The following are a few simple examples:
q
INTEGER variables Counter, Init, Final and Step are control-var, initial-value, final-value and step-size, respectively. INTEGER :: Counter, Init, Final, Step READ(*,*) Init, Final, Step DO Counter = Init, Final, Step ..... END DO
INTEGER variables i is the control-var. The initial-value and final-value are computed as the results of INTEGER expressions Upper-Lower and Upper+Lower, respectively. Since step-size is omitted, it is assumed to be 1. INTEGER :: i, Lower, Upper Lower = .... Upper = .... DO i = Upper - Lower, Upper + Lower ..... END DO
q q
Before the DO-loop starts, the values of initial-value, final-value and step-size are computed exactly once. More precisely, during the course of executing the DO-loop, these values will not be re-computed. step-size cannot be zero. If the value of step-size is positive (i.e., counting up): 1. The control-var receives the value of initial-value 2. If the value of control-var is less than or equal to the value of final-value, the statements part is executed. Then, the value of step-size is added to the value of control-var. Go back and compare the values of control-var and final-value.
Counting DO-Loop
3. If the value of control-var is greater than the value of final-value, the DO-loop completes and the statement following END DO is executed. If the value of step-size is negative (i.e., counting down): 1. The control-var receives the value of initial-value 2. If the value of control-var is greater than or equal to the value of final-value, the statements part is executed. Then, the value of step-size is added to the value of control-var. Go back and compare the values of control-var and final-value. 3. If the value of control-var is less than the value of final-value, the DO-loop completes and the statement following END DO is executed.
Examples
q
In the following, the control-var is Count. It receives -3 before the loop starts. It goes down the loop body and display the values of Count, Count*Count and Count*Count*Count. Thus, -3, 9, -27 are displayed. Then, 2 is added to Count changing its value from -3 to -1. Since this new value of Count (=-1) is less than the finalvalue, the loop body is executed and displays -1, 1, -1. Then, 2 is added to Count again, changing the value of Count to 1(=(-1)+2). Since this new value is still less than the final-value, the loop body is executed again. This time, it will display 1, 1, 1. Then, 2 is added to Count the third time, changing its value to 3. Since 3 is still less than the final-value, 3, 9, 27 are displayed. After adding 2 to the value of Count the fourth time, the new value of Count is finally greater than the final-value and the DO-loop completes. INTEGER :: Count
In the following, since steps-size is omitted, it is assumed to be 1. Therefore, the control-var Iteration receives 3, 4, and 5 in this order. INTEGER, PARAMETER :: Init = 3, Final = 5 INTEGER :: Iteration DO Iteration = Init, Final WRITE(*,*) 'Iteration ', Iteration END DO
The following uses two Fortran intrinsic functions MIN() and MAX(). It is a count-down loop. The initialvalue is the maximum of a, b and c, the final-value is the minimum of a, b and c, and the step-size is -2. Therefore, if the READ statement reads 2, 7, 5 into a, b and , then MAX(a,b,c) and MIN(a,b,c) are 7 and 2, respectively. As a result, control-var List will have values 7, 5, and 3. INTEGER :: a, b, c INTEGER :: List READ(*,*) a, b, c DO List = MAX(a, b, c), MIN(a, b, c), -2 WRITE(*,*) List
Counting DO-Loop
END DO
Adding numbers: Suppose the value of INTEGER variable Number has been given elsewhere, perhaps with a READ. The following code reads in Number integers and computes their sum into variable Sum. INTEGER :: Count, Number, Sum, Input Sum = 0 DO Count = 1, Number READ(*,*) Input Sum = Sum + Input END DO Sum is initialized to zero. For each iteration, the value of Input, which is read in with READ, is added to the value of Sum. For example, if the value of Number is 3, and the three input values are 3, 6, and 8 (on different lines), then the final value of Sum is 17 = 3+6+8. Let us look at it closely. Initially, Count receives a value of 1. Since 1 is less than the value of Number (=3), the loop body is executed. The READ statement reads the first input value 3 into Input and this value is added to Sum, changing its value from 0 to 1 (=0+1). Now, END DO is reached and the step-size (=1) is added to Count. Hence, the new value of Count is 2. Since Count is less than Number, the second input value is read into Input. Now, Input holds 6. Then, 6 is added to the value of Sum, changing its value to 9 (=3+6). The next iteration reads in 8 and adds 8 to Sum. The new value of Sum becomes 17 (=9+8). A simple modification can compute the average of all input numbers: INTEGER :: Count, Number, Sum, Input REAL :: Average Sum = 0 DO Count = 1, Number READ(*,*) Input Sum = Sum + Input END DO Average = REAL(Sum) / Number The above seems obvious. But, please note the use of the function REAL() that converts an INTEGER to a REAL. Without this conversion, Sum /Number is computed as dividing an integer by an integer, yielding an integer result. Consult singe mode arithmetic expressions for details. Factorial: A simple variation could be used to compute the factorial of a positive integer. The factorial of an
Counting DO-Loop
integer N, written as N!, is defined to be the product of 1, 2, 3, ..., N-1, and N. More precisely, N! = N*(N-1)* (N-2)*...*3*2*1. INTEGER :: Factorial, N, I Factorial = 1 DO I = 1, N Factorial = factorial * I END DO In the above, the DO-loop iterates N times. The first iteration multiplies Factorial with 1, the second iteration multiplies Factorial with 2, the third time with 3, ..., the i-th time with I and so on. Therefore, the values that are multiplied with the initial value of Factorial are 1, 2, 3, ..., N. At the end of the DO, the value of Factorial is 1*2*3*...*(N-1)*N.
The step-size cannot be zero. The following is not a good practice: INTEGER :: count DO count = -3, 4, 0 ... END DO
Do not change the value of the control-var. The following is not a good practice: INTEGER :: a, b, c DO a = b, c, 3 READ(*,*) a ! the value of a is changed a = b-c ! the value of a is changed END DO
Do not change the value of any variable involved in initial-value, final-value and step-size. The following is not a good practice: INTEGER :: a, b, c, d, e DO a = b+c, c*d, (b+c)/e READ(*,*) b ! initial-value is changed d = 5 ! final-value is changed e = -3 ! step-size is changed END DO
When you have a count-down loop, make sure the step-size is negative. If you have a positive step-size, the
Counting DO-Loop
body of the DO-loop will not be executed. See the way of executing a DO loop above. The body of the following DO will not be executed. INTEGER :: i DO i = 10, -10 ..... END DO
q
While you can use REAL type for control-var, initial-value, final-value and step-size, it would be better not to use this feature at all since it may be dropped in future Fortran standard. In the DO-loop below, x successively receives -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75 and 1.0. REAL :: x DO x = -1.0, 1.0, 0.25 ..... END DO You should not use this form of DO-loop in your programs. See the discussion of general DO for the details.
The first line gives the number of data values that follow Starting with the second line, each line contains an integer input value
For example, the following input shows that there are seven input values (i.e., the 7 on the first line), -6, 7, 2, -9, 0, 8 and 0. 7 -6 7 2 -9 0 8 0
Solution
! ! ! ! --------------------------------------------------------This program counts the number of positive and negative input values and computes their sums. ---------------------------------------------------------
PROGRAM Counting IMPLICIT NONE INTEGER INTEGER INTEGER INTEGER Positive Negative PosSum NegSum READ(*,*) :: :: :: :: = = = = Positive, Negative PosSum, NegSum TotalNumber, Count Data 0 0 0 0 TotalNumber ! ! ! ! # of positive items # of negative items sum of all positive items sum of all negative items
! read in # of items
DO Count = 1, TotalNumber ! for each iteration READ(*,*) Data ! read an item WRITE(*,*) 'Input data ', Count, ': ', Data IF (Data > 0) THEN ! if it is positive Positive = Positive + 1 ! count it PosSum = PosSum + Data ! compute their sum ELSE IF (Data < 0) THEN ! if it is negative Negative = Negative + 1 ! count it NegSum = NegSum + Data ! compute their sum END IF END DO WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) END PROGRAM ! display results 'Counting Report:' ' Positive items = ', Positive, ' Sum = ', PosSum ' Negative items = ', Negative, ' Sum = ', NegSum ' Zero items = ', TotalNumber - Positive - Negative 'The total of all input is ', Positive + Negative Counting
Counting Report: Positive items = 3 Sum = 17 Negative items = 2 Sum = -15 Zero items = 2 The total of all input is 5
Discussion
In the program, Positive and Negative are used to count the number of positive and negative data items, and PosSum and NegSum are used to compute their sums. The program first reads the number of input items into TotalNumber and uses it as the final value in a DO-loop. This loop iterates TotalNumber times. For each iteration, it reads in a new data into Data. The IF-THEN-ELSE-END IF statement tests to see if it is positive or negative, adds 1 into the corresponding counter, and adds the value into the corresponding sum. Note that the number of zero items are not counted, since TotalNumber - Positive - Negative gives the number of zero items. The sum of all zero items are not calculated either, since it must be zero!
Since computing geometric mean requires taking square root, it is further required that all input data values must be positive. As a result, this program must be able to ignore those non-positive items. However, this may cause all input items ignored. Therefore, before computing the means, this program should have one more check to see if there are valid items.
Solution
! ! ! ! ! ! ! ! ! ! ---------------------------------------------------------This program reads a series of input data values and computes their arithmetic, geometric and harmonic means. Since geometric mean requires taking n-th root, all input data item must be all positive (a special requirement of this program , although it is not absolutely necessary). If an input item is not positive, it should be ignored. Since some data items may be ignored, this program also checks to see if no data items remain! ----------------------------------------------------------
PROGRAM ComputingMeans IMPLICIT NONE REAL REAL REAL INTEGER :: :: :: :: X Sum, Product, InverseSum Arithmetic, Geometric, Harmonic Count, TotalNumber, TotalValid = = = = 0.0 1.0 0.0 0 ! ! ! ! for the sum for the product for the sum of 1/x # of valid items
TotalNumber
! read in # of items
DO Count = 1, TotalNumber ! for each item ... READ(*,*) X ! read it in WRITE(*,*) 'Input item ', Count, ' --> ', X IF (X <= 0.0) THEN ! if it is non-positive WRITE(*,*) 'Input <= 0. Ignored' ! ignore it ELSE ! otherwise, TotalValid = TotalValid + 1 ! count it in Sum = Sum + X ! compute the sum, Product = Product * X ! the product InverseSum = InverseSum + 1.0/X ! and the sum of 1/x END IF END DO IF (TotalValid > 0) THEN ! are there valid items? Arithmetic = Sum / TotalValid ! yes, compute means Geometric = Product**(1.0/TotalValid) Harmonic = TotalValid / InverseSum WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) ELSE WRITE(*,*) END IF END PROGRAM 'No. of valid items 'Arithmetic mean 'Geometric mean 'Harmonic mean --> ', TotalValid --> ', Arithmetic --> ', Geometric --> ', Harmonic ! no, display a message 'ERROR: none of the input is positive'
ComputingMeans
If the input data is 5 1.0 2.0 3.0 4.0 5.0 it will generate the following output. In this input, all data values are positive and none of them is ignored. Input item 1 --> 1. Input item 2 --> 2.
Input item 3 --> 3. Input item 4 --> 4. Input item 5 --> 5. No. of valid items Arithmetic mean Geometric mean Harmonic mean
q
5 3. 2.6051712 2.18978071
In the following input, the fourth value is negative. 6 1.0 2.0 3.0 -4.0 5.0 6.0 The output is shown below: Input Input Input Input Input Input Input item 1 item 2 item 3 item 4 <= 0. item 5 item 6 --> 1. --> 2. --> 3. --> -4. Ignored --> 5. --> 6. 6 5 3.4000001 2.82523465 2.27272725
# of items read --> # of valid items -> Arithmetic mean --> Geometric mean --> Harmonic mean -->
q
Now, let us try the following input in which all values are non-positive: 4 -1.0 -2.0 0.0 -3.0 We shall get the following output. The program correctly detects there is no valid data values and displays a message. Input Input Input Input item 1 <= 0. item 2 <= 0. --> -1. Ignored --> -2. Ignored
Discussion
This example is quite simple and does not require further explanation.
Computing Factorial
Computing Factorial
Problem Statement
The factorial of a non-negative integer n, written as n!, is defined as follows:
Write a program that reads in an integer and computes its factorial. This program should detect if the input is negative and display an error message.
Solution
! ! ! ! ! ! ---------------------------------------------------------Given a non-negative integer N, this program computes the factorial of N. The factorial of N, N!, is defined as N! = 1 x 2 x 3 x .... x (N-1) x N and 0! = 1. ----------------------------------------------------------
PROGRAM Factorial IMPLICIT NONE INTEGER :: N, i, Answer WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) READ(*,*) WRITE(*,*) 'This program computes the factorial of' 'a non-negative integer' 'What is N in N! --> ' N
IF (N < 0) THEN ! input error if N < 0 WRITE(*,*) 'ERROR: N must be non-negative' WRITE(*,*) 'Your input N = ', N ELSE IF (N == 0) THEN ! 0! = 1 WRITE(*,*) '0! = 1' ELSE ! N > 0 here Answer = 1 ! initially N! = 1 DO i = 1, N ! for each i = 1, 2, ..., N Answer = Answer * i ! multiply i to Answer
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/fact.html (1 of 3)8/5/2006 8:05:59 PM
Computing Factorial
Factorial
If the input is -5, a negative number, the program generates the following output indicating the input is wrong. This program computes the factorial of a non-negative integer What is N in N! --> -5 ERROR: N must be non-negative Your input N = -5
If the input is a zero, the output is 0! = 1. This program computes the factorial of a non-negative integer What is N in N! --> 0 0! = 1
If the input is 5, the factorial of 5 is 5!=1*2*3*4*5=120. This program computes the factorial of a non-negative integer What is N in N! --> 5 5! = 120
If the input is 15, the factorial of 15 is 15! = 1*2*3*...*13*14*15=2004310016 This program computes the factorial of a non-negative integer What is N in N! --> 15
Computing Factorial
15! = 2004310016
Discussion
The basics of writing a factorial computation program has been discussed in a factorial example of counting DO.
= ', z
One iteration of this loop consists of reading a value for x, computing its square and cube to y and z, respectively, and displaying the results. Then, the execution goes back to the top and executes the four statements again. Consequently, this loop is executed over and over and has no chance to stop at all. A loop that never stops is usually referred to as an infinite loop. To stop the iteration of a DO-loop, we need something else.
EXIT
DO statements-1 IF (logical-expression) THEN statements-THEN EXIT END IF statements-2 END DO For each iteration, statements in statements-1 are executed, followed the evaluation of the logical-expression. If the result is .FALSE., statements in statements-2 are executed. This completes one iteration and the control goes back to the top and executes statements-1 again for next iteration. If the result of evaluating logical-expression is .TRUE., the first form will executes EXIT, which immediately stops the execution of the DO-loop. The next statement to be executed is the one following END DO. For the second form, if the result of evaluating logical-expression is .TRUE., statements in statements-THEN are executed followed by the EXIT statement, which brings the execution to the statement following END DO. Therefore, statements in statements-THEN will do some "house-keeping" work before leaving the DO-loop. If there is no "house-keeping" work, the first form will suffice.
Examples
q
The following code reads in values into variable x until the input value becomes negative. All input values are added to Sum. Note that the negative one is not added to Sum, since once the code sees such a negative value, EXIT is executed. INTEGER :: x, Sum Sum = 0 DO READ(*,*) x IF (x < 0) EXIT Sum = Sum + x END DO
The following is an example that "simulates" a counting DO-loop using REAL variables. Variable x is initialized to the initial value Lower and serves as a control variable. Before any statement of the DO-loop is executed, the value of x is checked to see if it is greater than the final value Upper. If it is, EXIT is executed, leaving the loop. Otherwise, the loop body is executed and before goes back to the top, the control variable x must be increased by the step size Step. This loop will display -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75 and 1.0, each of them is on a separate line. REAL, PARAMETER :: Lower = -1.0, Upper = 1.0, Step = 0.25
REAL
:: x
x = Lower ! initialize the control variable (DON'T FORGET) DO IF (x > Upper) EXIT ! is it > final-value? WRITE(*,*) x ! no, do the loop body x = x + Step ! an increase by step-size END DO
q
In many cases, your program may expect an input satisfying certain conditions. DO-loop can help a lot. The following code keeps asking and checking if the input integer value is in the range of 0 and 10 inclusive. If it is not, the program warns the user and reads again until the input is in the stated range. INTEGER :: Input DO WRITE(*,*) 'Type an integer in the range of 0 and 10 please --> ' READ(*,*) Input IF (0 <= Input .AND. Input <= 10) EXIT WRITE(*,*) 'Your input is out of range. Try again' END DO
One of the most commonly seen problem is forgetting to change the logical-expression that may cause an EXIT. The following DO-loop never stops and keeps displaying 5, 5, 5, 5, ..., forever. The reason? The value of i is never changed. INTEGER :: i
i = 5 DO IF (i < -2) EXIT WRITE(*,*) i END DO The following is another example: INTEGER :: i = 1, j = 5 DO IF (j < 0) WRITE(*,*) i = i + 1 END DO
q
EXIT i
Sometimes we just forget to initialize the control-var . We really do not know what would be displayed since the value of i is unknown at the beginning of the DO and is certainly unknown after executing i = i - 1.
Solution
! ! ! ! ! -----------------------------------------------------This program reads in a number of integer input until a negative one, and determines the minimum and maximum of the input data values. ------------------------------------------------------
PROGRAM MinMax IMPLICIT NONE INTEGER :: Minimum, Maximum INTEGER :: Count INTEGER :: Input ! max and min ! # of data items ! the input value
Count = 0 ! initialize counter DO ! for each iteration READ(*,*) Input ! read in a new input IF (Input < 0) EXIT ! if it is < 0, done. Count = Count + 1 ! if >= 0, increase counter WRITE(*,*) 'Data item #', Count, ' = ', Input IF (Count == 1) THEN ! is this the 1st data? Maximum = Input ! yes, assume it is the Minimum = Input ! min and the max ELSE ! no, not the 1st data IF (Input > Maximum) Maximum = Input ! compare against the IF (Input < Minimum) Minimum = Input ! existing min & max
END IF END DO WRITE(*,*) IF (Count > 0) WRITE(*,*) WRITE(*,*) WRITE(*,*) ELSE WRITE(*,*) END IF END PROGRAM
THEN ! if at one data item found 'Found ', Count, ' data items' ' Maximum = ', Maximum ' Minimum = ', Minimum 'No data item found.' ! no data item found
MinMax
Discussion
q q q q
The data reading scheme is easy and will not be discussed. It has been discussed in an example of general DO. Variable Count is used for counting the number of data items. Once a non-negative item is read in, the value of Count is increased by 1 and the input value is displayed. If this is the first value (i.e., Count being 1), it is the maximum and the minimum value we have seen so far. Therefore, the value of Input is saved in Minimum and Maximum which hold the minimum and maximum values seen so far. If it is not the first input value, then Input is compared against Minimum and Maximum. If Input is less than Minimum, then the new value is less than the minimum so far and should become the new minimum. Likewise, if Input is greater than Maximum, then the new value is greater than the maximum so far and should become the new maximum. These activities are handled in the ELSE part. After all input are read, Count should be checked again to see if there is any input value at all. If there are, the count, minimum and maximum are displayed; otherwise, a message is displayed.
where x above starts with a "reasonable" guess. In fact, you can always start with b or some other value, say 1. With b and a guess value x, a new guess value is computed with the above formula. This process continues until the new guess value and the current guess value are very close. In this case, either one can be considered as an approximation of the square root of b. Write a program that reads in a REAL value and a tolerance, and computes the square root until the absolute error of two adjacent guess values is less than the tolerance value.
Solution
! ! ! ! ! ! ! --------------------------------------------------------This program uses Newton's method to find the square root of a positive number. This is an iterative method and the program keeps generating better approximation of the square root until two successive approximations have a distance less than the specified tolerance. ---------------------------------------------------------
PROGRAM SquareRoot IMPLICIT NONE REAL :: Input, X, NewX, Tolerance INTEGER :: Count READ(*,*) Input, Tolerance ! count starts with 0 ! X starts with the input value ! for each iteration ! increase the iteration count ! compute a new approximation EXIT ! if they are very close, exit ! otherwise, keep the new one
Count = 0 X = Input DO Count = Count + 1 NewX = 0.5*(X + Input/X) IF (ABS(X - NewX) < Tolerance) X = NewX END DO
'After ', Count, ' iterations:' ' The estimated square root is ', NewX ' The square root from SQRT() is ', SQRT(Input) ' Absolute error = ', ABS(SQRT(Input) - NewX) SquareRoot
Discussion
q
This program uses X to hold the input value for b and uses NewX to hold the new guess value. The initial guess is the input value. From the current guess, using Newton's formula, the new guess is compared as NewX = 0.5*(X + Input/X)
Then, the absolute error of X and NewX is computed. If it is less than the tolerance value, EXIT the loop and display the results. Otherwise, the current guess is replaced with the new guess and go back for the next iteration.
Computing EXP(x)
Computing EXP(x)
Problem Statement
The exponential function, EXP(x), is defined to be the sum of the following infinite series:
Write a program that reads in a REAL value and computes EXP() of that value using the series until the absolute value of a term is less than a tolerance value, say 0.00001.
Solution
! ! ! ! ! ! ! ! --------------------------------------------------------This program computes exp(x) for an input x using the infinite series of exp(x). This program adds the terms together until a term is less than a specified tolerance value. Thus, two values are required: the value for x and a tolerance value. In this program, he tolerance value is set to 0.00001 using PARAMETER. ---------------------------------------------------------
PROGRAM Exponential IMPLICIT NONE INTEGER REAL REAL REAL REAL, PARAMETER :: :: :: :: :: Count ! Term ! Sum ! X ! Tolerance = 0.00001 ! ! ! ! ! ! ! ! ! # of terms used a term the sum of series the input x ! tolerance read in x the first term is 1 and counted thus, the sum starts with 1 the second term is x for each term if too small, exit otherwise, add to sum count indicates the next term compute the value of next term
READ(*,*) X Count = 1 Sum = 1.0 Term = X DO IF (ABS(Term) < Tolerance) Sum = Sum + Term Count = Count + 1 Term = Term * (X / Count) END DO
EXIT
Computing EXP(x)
'After ', Count, ' iterations:' ' Exp(', X, ') = ', Sum ' From EXP() = ', EXP(X) ' Abs(Error) = ', ABS(Sum - EXP(X)) Exponential
Discussion
q
One obvious way of writing this program is computing each term directly using the formula xi/i!. However, this is not a wise way, since both xi and i! could get very large when x or i is large. One way to overcome this problem is rewriting the term as follows:
Therefore, the (i+1)-th term is equal to the product of the i-th term and x/(i+1). In the program, variable Term is used to save the value of the current term and is updated with Term = Term * (X / Count) where Count is the value of i+1. Variable Sum is used to accumulate the values of terms. Since the tolerance value is usually small, the first term whose value is 1 cannot be less than the tolerance value. Therefore, the computation starts with the second term and 1 is saved to Sum.
q q
Computing EXP(x)
q q q
Count indicates which term is under consideration. Its plays the role of i in the infinite series shown above. Since the computation starts with the first term, the value of the first term, x, is saved to Term. For each iteration, the absolute value of Term is checked to see if it is less than the tolerance value Tolerance. If it is, the computation is done and EXIT. Otherwise, this term is added to Sum and prepare for the next term. Before this, Count is increased by one to point to the next term and consequently the next term is computed as Term * (X / Count).
Solution
! ! ! ! ! ! ! ! --------------------------------------------------------This program computes the GCD of two positive integers using the Euclid method. Given a and b, a >= b, the Euclid method goes as follows: (1) dividing a by b yields a reminder c; (2) if c is zero, b is the GCD; (3) if c is no zero, b becomes a and c becomes c and go back to Step (1). This process will continue until c is zero. ---------------------------------------------------------
WRITE(*,*) 'Two positive integers please --> ' READ(*,*) a, b IF (a < b) THEN ! since a >= b must be true, they c = a ! are swapped if a < b a = b b = c END IF DO c = MOD(a, b) IF (c == 0) EXIT a = b b = c ! now we have a <= b ! compute c, the reminder ! if c is zero, we are done. ! otherwise, b becomes a ! and c becomes b
GCD = b
END DO
go back
If the input values are 46332 and 71162, the computed GCD is 26. Two positive integers please --> 46332 71162 The GCD is 26
If the input values are 128 and 32, the GCD is 32. Two positive integers please --> 128 32 The GCD is 32
If the input values are 100 and 101, the GCD is 1 and 100 and 101 are relatively prime. Two positive integers please --> 100 101 The GCD is 1
If the input values are 97 and 97, the GCD is of course 97. Two positive integers please --> 97 97 The GCD is 97
Discussion
q
q q
Since there is no specific order for the two input values, it is possible that a may be less than b. In this case, these two values must be swapped. Thus, before entering the DO-loop, we are sure that a >= b holds. Then, the remainder is computed and stored to c. If c is zero, the program EXITs and displays the value of b as the GCD. The remainder is computed using Fortran intrinsic function MOD(). If c is not zero, b becomes a and c becomes b, and reiterates.
If we need to display the result as follows: The GCD of 46332 and 71162 is 26 would the following change to the WRITE statement work? WRITE(*,*) 'The GCD of ', a, ' and ', b, ' is ', b
Solution
! ! ! ! ! ! ! ! ! ! ! -------------------------------------------------------------------Given an integer, this program determines if it is a prime number. This program first makes sure the input is 2. In this case, it is a prime number. Then, it checks to see the input is an even number. If the input is odd, then this program divides the input with 3, 5, 7, ....., until one of two conditions is met: (1) if one these odd number evenly divides the input, the input is not a prime number; (2) if the divisor is greater than the square toot of the input, the input is a prime. --------------------------------------------------------------------
PROGRAM Prime IMPLICIT NONE INTEGER INTEGER :: Number :: Divisor ! the input number ! the running divisor
READ(*,*) Number ! read in the input IF (Number < 2) THEN ! not a prime if < 2 WRITE(*,*) 'Illegal input' ELSE IF (Number == 2) THEN ! is a prime if = 2 WRITE(*,*) Number, ' is a prime' ELSE IF (MOD(Number,2) == 0) THEN ! not a prime if even WRITE(*,*) Number, ' is NOT a prime' ELSE ! we have an odd number here Divisor = 3 ! divisor starts with 3 DO ! divide the input number IF (Divisor*Divisor > Number .OR. MOD(Number, Divisor) == 0) Divisor = Divisor + 2 ! increase to next odd END DO IF (Divisor*Divisor > Number) THEN ! which condition fails? WRITE(*,*) Number, ' is a prime' ELSE WRITE(*,*) Number, ' is NOT a prime' END IF
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/prime-1.html (1 of 3)8/5/2006 8:06:16 PM
EXIT
Prime
If the input value is -1, the output is a message saying the input is not legal. Illegal input
If the input is 46, it is not a prime number since it is divisible by 2. 46 is NOT a prime
If the input is 9797, it is not a prime since it is divisible by 97. 9797 is NOT a prime
Discussion
q
Since the input is an arbitrary integer, the program first makes sure its value is greater than or equal to 2; otherwise, a message is displayed. If the input is greater than or equal to 2, the program checks if it is actually equal to 2. If it is, just reports "2 is a prime". The next step is screening out all even numbers. Note that 2 has been checked before the control gets to the second ELSE-IF. If the input is divisible by 2, it is not a prime number. If the control can reach here, the input is an odd number greater than or equal to 3. Then, the program uses 3, 5, 7, 9, 11, ... these odd numbers as divisors to divide the input value stored in Number. These divisors are successively stored in Divisor. Of course, these divisors should start with 3; but, the question is when to stop. A naive answer would be "let us try up to Number-1" This is too slow since Number cannot be evenly divided by Number-1. A better choice is the square root of Number? Why is this strange value? If Number is divisible by a, then we can
write Number=a*b for some b. If a is less than or equal to b, then a must be smaller than or equal to the square root of Number. Therefore, the upper limit of Divisor is the square root of Number. Stated in a slightly different way, it is "the square of Divisor is less than or equal to Number". This is better since it only uses integer arithmetic, while the one using square root involves REAL numbers. In the DO-loop, the value for Divisor starts with 3. As long as the square of Divisor is less than or equal to Number and Number is not divisible by Divisor, the iteration continues. Since Divisor can only be odd numbers, step-size is 2. This loop continues until one of the two conditions holds. If Divisor*Divisor > Number holds, then all odd numbers that are greater than or equal to 3 and less than or equal to the square root of Number have been tried and none of them can evenly divide Number. Therefore, Number is a prime number. If MOD(Number,Divisor) == 0 holds, Divisor divides Number and Number is not a prime. Let us take a look at a few examples: 1. Let Number be 3. Divisor starts with 3. Since condition Divisor*Divisor > Number holds immediately, 3 is a prime number. 2. Let Number be 5. Divisor starts with 3. Since condition Divisor*Divisor > Number holds immediately, 5 is a prime number. 3. Let Number be 11. Divisor starts with 3. In the first iteration, both Divisor*Divisor > Number and MOD (Number,Divisor) == 0 fail. So, Divisor is increased by 2, becoming 5. In the second iteration, Divisor*Divisor > Number holds and 11 is a prime. 4. Let Number be 91. Divisor starts with 3. In the first iteration, both Divisor*Divisor > Number and MOD (Number,Divisor) == 0 fail. So, Divisor is increased by 2, becoming 5. In the second iteration, both conditions still fail and Divisor is increased to 7. In the third iteration, MOD(Number,Divisor) == 0 holds and 91 is not a prime.
Nested DO-Loops
Nested DO-Loops
Just like an IF-THEN-ELSE-END IF can contain another IF-THEN-ELSE-END IF (see nested IF for the details), a DOloop can contain other DO-loops in its body. The body of the contained DO-loop, usually referred to as the nested DOloop, must be completely inside the containing DO-loop. Note further that an EXIT statement only brings the control out of the inner-most DO-loop that contains the EXIT statement. Suppose we have the following nested DO loops: DO statements-1 DO statement-2 END DO statement-3 END DO Each iteration of the outer DO starts with statements-1. When the control reaches the inner DO, statements-2 is executed until some condition of the inner DO brings the control out of it. Then, statements-3 is executed and this completes one iteration. Any EXIT in the inner DO brings the control out of the inner DO to the first statement in statement-3. The following are a few simple examples:
q
In the following nested loops, the outer one has i running from 1 to 9 with step size 1. For each iteration, say the i-th one, the inner loop iterates 9 times with values of j being 1, 2, 3, 4, 5, 6, 7, 8, 9. Therefore, with i fixed, the WRITE is executed 9 times and the output consists of i*1, i*2, i*3, ..., i*9. INTEGER :: i, j DO i = 1, 9 DO j = 1, 9 WRITE(*,*) END DO END DO
i*j
Once this is done, the value of i is advanced to the next one, and the inner loop will iterate 9 times again displaying the product of the new i and 1, 2, 3,4 ..., 9. The net effect is a multiplication table. For i=1, the value if 1*1, 1*2, 1*3, ..., 1*9 are displayed; for i=2, the displayed values are 2*1, 2*2, 2*3, ..., 2*9; ...; for i=9, the displayed values are 9*1, 9*2, 9*3, ..., 9*9.
q
The following shows a nested DO-loop. The outer one lets u run from 2 to 5. For each u, the inner DO lets v runs from 1 to u-1. Therefore, when u is 2, the values for v is from 1 to 1. When u is 3, the values for v are 1 and 2. When u is 4, the values for v are 1, 2, and 3. Finally, when u is 5, the values for v are 1, 2, 3 and 4. INTEGER :: u, v
Nested DO-Loops
INTEGER :: a, b, c DO u = 2, 5 DO v = 1, u-1 a = 2*u*v b = u*u - v*v c = u*u + v*v WRITE(*,*) a, b, c END DO END DO The above discussion can be summarized in the following table: u Values for v 2 1 3 1 2 4 1 2 3 5 1 2 3 4 For each pair of u and v, the inner loop computes a, b and c. Thus, it will generate the following result (please verify it): u v a 2 1 4 3 1 6 b 3 c 5
8 10
2 12 5 13 1 8 15 17
4 2 16 12 20 3 24 7 25 1 10 24 26 5 2 20 21 29 3 30 16 34 4 40 9 41
q
It is obvious that the inner DO-loop computes the sum of all integers in the range of 1 and i (i.e., Sum is equal to 1+2+3+...+i). Since i runs from 1 to 10, the following loop computes ten sums: 1, 1+2, 1+2+3, 1+2+3+4, ...., 1 +2+3+...+9, and 1+2+3+...+9+10. INTEGER :: i, j, Sum DO i = 1, 10 Sum = 0 DO j = 1, i Sum = Sum + j
Nested DO-Loops
Sum
The program below uses Newton's method for computing the square root of a positive number. In fact, it computes the square roots of the numbers 0.1, 0.1, ..., 0.9 and 1.0. REAL :: Start = 0.1, End = 1.0, Step = 0.1 REAL :: X, NewX, Value Value = Start DO IF (Value > End) EXIT X = Value DO NewX = 0.5*(X + Value/X) IF (ABS(X - NewX) < 0.00001) EXIT X = NewX EBD DO WRITE(*,*) 'The square root of ', Value, ' is ', NewX Value = Value + Step END DO Newton's method is taken directly from the programming example, where X is the current guess, NewX is the new guess, and Value is the number for square root computation. The EXIT statement brings the execution of the inner DO to the WRITE statement. If the inner loop is removed, we have the outer loop as follows: REAL :: Start = 0.1, End = 1.0, Step = 0.1 REAL :: X, NewX, Value Value = Start DO IF (Value > End) EXIT ! ! the inner loop computes the result in NewX ! WRITE(*,*) 'The square root of ', Value, ' is ', NewX Value = Value + Step END DO It is clear that the value of Value starts with 0.1 and have a step size 0.1 until 1.0. Thus, the values of Value are 0.1, 0.2, 0.3, ..., 0.9 and 1.0. For each value of Value, the inner loop computes the square root of Value. The EXIT statement in the outer loop brings the control out of the outer loop.
100.0 98.0 85.0 80.0 75.0 85.0 97.0 76.0 65.0 99.0 74.0 90.0 90.0 98.0 65.0 50.0 96.0 81.0
The first number 4 gives the number of classes in this file. For each class, it starts with an integer, giving the number of students in that class. Thus, the first class has 3 students, the second has 2, the third has 4 and the fourth has 3. Following the number of students, there are that number of lines each of which contains the three scores of a student. Write a program that reads in a file of this form and computes the following information: 1. the average of each student; 2. the class average of each exam; and 3. the grant average of the class. Click here to download this data file.
Solution
! ! ! ! ! ! ! ---------------------------------------------------------This program computes the average of each student and the the average of the class. The input file starts with an integer giving the number of classes. For each class, the input starts with an integer giving the number of students of that class, followed that number of lines on each of which there are three scores. This program reads in the
! scores and computes their average and also the class ! averages of each score and the grant average of the class. ! ---------------------------------------------------------PROGRAM ClassAverage IMPLICIT NONE INTEGER INTEGER INTEGER REAL REAL :: :: :: :: :: NoClass ! the no. of classes NoStudent ! the no. of students in each class Class, Student ! DO control variables Score1, Score2, Score3, Average Average1, Average2, Average3, GrantAverage
READ(*,*) NoClass ! read in the # of classes DO Class = 1, NoClass ! for each class, do the following READ(*,*) NoStudent ! the # of student in this class WRITE(*,*) WRITE(*,*) 'Class ', Class, ' has ', NoStudent, ' students' WRITE(*,*) Average1 = 0.0 ! initialize average variables Average2 = 0.0 Average3 = 0.0 DO Student = 1, NoStudent ! for each student in this class READ(*,*) Score1, Score2, Score3 ! read in his/her scores Average1 = Average1 + Score1 ! prepare for class average Average2 = Average2 + Score2 Average3 = Average3 + Score3 Average = (Score1 + Score2 + Score3) / 3.0 ! average of this one WRITE(*,*) Student, Score1, Score2, Score3, Average END DO WRITE(*,*) '----------------------' Average1 = Average1 / NoStudent ! class average of score1 Average2 = Average2 / NoStudent ! class average of score2 Average3 = Average3 / NoStudent ! class average of score3 GrantAverage = (Average1 + Average2 + Average3) / 3.0 WRITE(*,*) 'Class Average: ', Average1, Average2, Average3 WRITE(*,*) 'Grant Average: ', GrantAverage END DO END PROGRAM ClassAverage
3, 65., 70., 76., 70.3333359 ---------------------Class Average: 87.3333359, 78.3333359, Grant Average: 83.5555573 Class 2 has 2 students 1, 100., 100., 98., 99.3333359 2, 97., 85., 80., 87.3333359 ---------------------Class Average: 98.5, 92.5, 89. Grant Average: 93.3333359 Class 3 has 4 students 1, 78., 75., 90., 81. 2, 89., 85., 90., 88. 3, 100., 97., 98., 98.3333359 4, 56., 76., 65., 65.6666641 ---------------------Class Average: 80.75, 83.25, 85.75 Grant Average: 83.25 Class 4 has 3 students 1, 60., 65., 50., 58.3333321 2, 100., 99., 96., 98.3333359 3, 87., 74., 81., 80.6666641 ---------------------Class Average: 82.3333359, 79.3333359, Grant Average: 79.1111145
85.
75.6666641
Discussion
This is a relatively easy problem. Here is an analysis in case you need it. Since for each class we need to compute the average of each student, the class average of each exam, and the grant average of the whole class, we might immediately come up the following scheme: READ(*,*) DO Class = compute display END DO NoClass 1, NoClass various average for this class exam averages and class the grant average
Thus, "compute various average for the class" becomes the job of the inner loop. This loop should read in the scores of each student and do some computation as follows: READ(*,*) NoStudent DO Student = 1, NoStudent
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/means-3.html (3 of 4)8/5/2006 8:06:22 PM
READ(*,*) Score1, Score2, Score3 compute the average of this student compute the exam averages END DO Now, the only trouble is how to compute the exam averages. In fact, this inner loop has no way to compute the exam averages directly; but, it could compute the sum of the scores of a particular exam. After this inner loop ends, the outer loop could divide the sum with the number of students to obtain the average. To accumulate these sums, we need to initialize variables. Thus, the result is: Average1 = 0.0 Average2 = 0.0 Average3 = 0.0 DO Student = 1, NoStudent READ(*,*) Score1, Score2, Score3 Average1 = Average1 + Score1 Average2 = Average2 + Score2 Average3 = Average3 + Score3 Average = (Score1 + Score2 + Score3) / 3.0 WRITE(*,*) Student, Score1, Score2, Score3, Average END DO WRITE(*,*) '----------------------' Average1 = Average1 / NoStudent Average2 = Average2 / NoStudent Average3 = Average3 / NoStudent GrantAverage = (Average1 + Average2 + Average3) / 3.0 In the above, Average1, Average2 and Average3 are for the exam averages. They must be initialized right before entering the inner DO-loop, since the exam averages are computed for each class. The actual average is computed right after the inner DOloop by dividing Average1, Average2 and Average3 with the number of students NoStudents. Once we have the exam averages, the grant average is computed as the average of these exam averages.
Write a program that reads in an initial value Begin, a final value End and a step size Step, and computes the exponential function value at Begin, Begin+Step, Begin+2*Step, ...
Solution
! ! ! ! ! ! ! ! ! -------------------------------------------------------------This program computes exp(x) for a range of x. The range is in the form of beginning value, final value and step size. For each value in this range, the infinite series of exp(x) is used to compute exp(x) up to a tolerance of 0.00001. This program display the value of x, the exp(x) from infinite series, the exp(x) from Fortran's intrinsic function exp(x), the absolute error, and the relative error. --------------------------------------------------------------
PROGRAM Exponential IMPLICIT NONE INTEGER REAL REAL REAL REAL REAL REAL, PARAMETER WRITE(*,*) READ(*,*) :: :: :: :: :: :: :: Count ! Term ! Sum ! X ! ExpX ! Begin, End, Step ! Tolerance = 0.00001 term count a term the sum of series running value EXP(X) control values ! tolerance
'Initial, Final and Step please --> ' Begin, End, Step ! X starts with the beginning value EXIT ! if X is > the final value, EXIT ! the first term is 1 and counted ! thus, the sum starts with 1
Term = X ExpX = EXP(X) DO IF (ABS(Term) < Tolerance) Sum = Sum + Term Count = Count + 1 Term = Term * (X / Count) END DO WRITE(*,*) X = X + Step END DO END PROGRAM Exponential
! ! ! EXIT ! ! !
the second term is x the exp(x) from Fortran's EXP() for each term ! if too small, exit otherwise, add to sum count indicates the next term compute the value of next term
You may find out that the value for X are not -1.0, -0.9, -0.8, ..., 0.0, 0.1, 0.2, ..., 0.9 and 1.0. It contains errors. For example, the last value should be 1.0 instead of 0.900000155. This is a problem of precision being not high enough. See the KIND attribute in a later chapter.
Discussion
q q
For the computation using infinite series, see a previous example for the details. Since the data points are Begin, Begin+Step, Begin+2*Step and so on, it is simply a DO-loop as follows: X = Begin DO IF (X > End) EXIT ... compute EXP(X) here ... X = X + Step END DO
Inserting the computation part into the place "... computing EXP(X) here ..." gives the program shown above.
Armstrong Numbers
Armstrong Numbers
Problem Statement
An Armstrong number of three digits is an integer such that the sum of the cubes of its digits is equal to the number itself. For example, 371 is an Armstrong number since 3**3 + 7**3 + 1**3 = 371. Write a program to find all Armstrong number in the range of 0 and 999.
Solution
! ! ! ! ! ! ! --------------------------------------------------------------This program computes all Armstrong numbers in the range of 0 and 999. An Armstrong number is a number such that the sum of its digits raised to the third power is equal to the number itself. For example, 371 is an Armstrong number, since 3**3 + 7**3 + 1**3 = 371. ---------------------------------------------------------------
PROGRAM ArmstrongNumber IMPLICIT NONE INTEGER :: a, b, c INTEGER :: abc, a3b3c3 INTEGER :: Count ! the three digits ! the number and its cubic sum ! a counter
Count = 0 DO a = 0, 9 ! for the left most digit DO b = 0, 9 ! for the middle digit DO c = 0, 9 ! for the right most digit abc = a*100 + b*10 + c ! the number a3b3c3 = a**3 + b**3 + c**3 ! the sum of cubes IF (abc == a3b3c3) THEN ! if they are equal Count = Count + 1 ! count and display it WRITE(*,*) 'Armstrong number ', Count, ': ', abc END IF END DO END DO END DO END PROGRAM ArmstrongNumber
Armstrong Numbers
Discussion
q
Three-digit numbers are 000, 001, 002, ..., 009, 010, 011, ..., 019, 020, 021, 022, ..., 099, 100, 101, 102, ..., 109, 110, ... 990, 991, ..., 999. As you can see the right-most digits changes faster than the middle one, which in turn is faster than the left-most one. As the left-most and the middle digits are fixed to 0 and 0, the right-most digit changes from 0 to 9. Then, the middle one is increased from 0 to 1. In other words, whenever the right-most digit completes a 0 to 9 cycle, the middle digit is increased by one and the right-most digit restart another 0 to 9 cycle. By the same token, whenever the middle digit completes a 0 to 9 cycle, the left-most digit is increased by 1 and the middle digit restarts another 0 to 9 cycle. Therefore, if a, b and c are the left-most, the middle and the right-most digits, the above discussion is formalized with the following three nested DO-loops: DO a = 0, 9 DO b = 0, 9 DO c = 0, 9 ... the number is abc ..... END DO END DO END DO
Now, in the inner most DO, the number in hand is abc, where a, b and c are the left-most, middle and the right-most digits. The number itself is of course a*100 + b*10 + c. The sum of the cubes of the digits is a**3 + b**3 + c**3. In the program, these two are stored in abc and a3b3c3, respectively. Finally, if abc and a3b3c3 are equal, we have found an Armstrong number. We can use abc or a3b3c3
Solution
! ! ! ! --------------------------------------------------------------This program finds all prime numbers in the range of 2 and an input integer. ---------------------------------------------------------------
WRITE(*,*) 'What is the range ? ' DO READ(*,*) Range IF (Range >= 2) EXIT WRITE(*,*) 'The range value must WRITE(*,*) 'Please try again:' END DO
! keep trying to read a good input ! ask for an input integer ! if it is GOOD, exit be >= 2. Your input = ', Range ! otherwise, bug the user
Count = 1 ! input is correct. start counting WRITE(*,*) ! since 2 is a prime WRITE(*,*) 'Prime number #', Count, ': ', 2 DO Number = 3, Range, 2 ! try all odd numbers 3, 5, 7, ... Divisor = 3 ! divisor starts with 3 DO IF (Divisor*Divisor > Number .OR. MOD(Number,Divisor) == 0) EXIT Divisor = Divisor + 2 ! if does not evenly divide, next odd END DO IF (Divisor*Divisor > Number) THEN ! are all divisor exhausted? Count = Count + 1 ! yes, this Number is a prime WRITE(*,*) 'Prime number #', Count, ': ', Number END IF END DO
'There are ', Count, ' primes in the range of 2 and ', Range Primes
The following shows an interaction between the user and program. First, the users type in -10, which is less than 2. This program displays the input value and a message asking the user to try again. The user then types in 0, which is still less than 2, causing the same message to occur. The users types in 1 and the same message appears. Finally, after the user types in 5, the program reports that there are three prime numbers in the range of 2 and 5, namely: 2, 3, and 5. What is the range ? -10 The range value must be >= 2. Please try again: 0 The range value must be >= 2. Please try again: 1 The range value must be >= 2. Please try again: 5 Prime number #1: 2 Prime number #2: 3 Prime number #3: 5 There are 3 primes in the range of 2 and 5
Your input = 0
Your input = 1
The following is generated with input 100. There are 25 prime numbers in the range of 2 and 100. What is the range ? 100 Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime number number number number number number number number number number number number #1: 2 #2: 3 #3: 5 #4: 7 #5: 11 #6: 13 #7: 17 #8: 19 #9: 23 #10: 29 #11: 31 #12: 37
Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime
number number number number number number number number number number number number number
#13: #14: #15: #16: #17: #18: #19: #20: #21: #22: #23: #24: #25:
41 43 47 53 59 61 67 71 73 79 83 89 97
Discussion
q
We shall use part of the program shown in a previous example for checking if an integer is a prime number. Please refer to that example for the details. How do we write a bullet-proof program so that the values for N and Range in the program are always correct? Here is the way our program uses: WRITE(*,*) 'What is the range ? ' DO READ(*,*) Range IF (Range >= 2) EXIT ... incorrect input here ... END DO It first asks for a number. The actual READis in the DO-loop. After reading in a value for Range, this value is checked to see if it is greater than or equal to 2. If it is, EXITand find prime numbers, since we have read in a good input. Otherwise, the input is incorrect and the program shows a message and loops back to read a new one. After reading in a correct value for Range, we can start prime number searching. Since Range is larger than or equal to 2, 2 must be included since it is a prime number. All the other prime numbers are odd numbers. As a result, we only try to determine if a number in the list of 3, 5, 7, 9, 11, ...., up to Range, is a prime number. This is, of course, the job of a DO-loop: DO Number = 3, Range, 2 ... determine if Number is a prime number ... ... if Number is a prime number, display it ... END DO
The segment in the previous example can be used to replace "...determine if Number is a prime number..." and the final program is the one shown above.
Thus, 586390350 has factors 2, 3, 5, 5,, 7, 7, 13, 17, 19 and 19. Note that all factors are prime numbers. Write a program that reads in an integer greater than or equal to 2 and finds all of its prime factors. This problem is a little more difficult than the others and may require longer time to understand its logic.
Solution
! ! ! ! ! ! ! --------------------------------------------------------------This program determines all prime factors of an n integer >= 2. It first removes all factors of 2. Then, removes all factors of 3, 5, 7, and so on. All factors must be prime numbers since when a factor is tried all of whose non-prime factors have already been removed. ---------------------------------------------------------------
PROGRAM Factorize IMPLICIT NONE INTEGER INTEGER INTEGER :: Input :: Divisor :: Count 'This program factorizes any integer >= 2 --> ' Input
WRITE(*,*) READ(*,*)
Count = 0 DO ! here, we try to remove all factors of 2 IF (MOD(Input,2) /= 0 .OR. Input == 1) EXIT Count = Count + 1 ! increase count WRITE(*,*) 'Factor # ', Count, ': ', 2 Input = Input / 2 ! remove this factor from Input END DO Divisor = 3 DO ! now we only worry about odd factors ! 3, 5, 7, .... will be tried
IF (Divisor > Input) EXIT ! if a factor is too large, exit and done DO ! try this factor repeatedly IF (MOD(Input,Divisor) /= 0 .OR. Input == 1) EXIT Count = Count + 1 WRITE(*,*) 'Factor # ', Count, ': ', Divisor Input = Input / Divisor ! remove this factor from Input END DO Divisor = Divisor + 2 ! move to next odd number END DO END PROGRAM Factorize
If the input is 100, the output consists of four factors 2, 2, 5 and 5. This program factorizes any integer >= 2 --> 100 Factor Factor Factor Factor # # # # 1: 2: 3: 4: 2 2 5 5
If the input is 16, the output consists of four factors 2, 2, 2 and 2. This program factorizes any integer >= 2 --> 16 Factor Factor Factor Factor # # # # 1: 2: 3: 4: 2 2 2 2
If the input is 53, since it is a prime number, the output has only one factor: 53 itself. This program factorizes any integer >= 2 --> 53 Factor # 1: 53
If the input value is 586390350, the output consists of 10 factors 2, 3, 5, 5, 7, 7, 13, 17, 19 and 19. This program factorizes any integer >= 2 --> 586390350 Factor # 1: 2 Factor # 2: 3
# # # # # # # #
3: 5 4: 5 5: 7 6: 7 7: 13 8: 17 9: 19 10: 19
Discussion
q
How to remove a factor from a given number? I believe you have learned it in high school. Let the given number be n and we know x is a factor of n. Then, we just keep dividing n by x until the quotient is 1 or x cannot evenly divide n. For example, 3 is a factor of 72. The first division yields a quotient 24=72/3. The second division yields a quotient 8=24/3. Thus, the original number 72 has two factors of 3. If n and x are both 53, then the first division yields a quotient 1=53/53. Since the quotient is 1, no more division is necessary and 53 has a factor 53! So, how to convert the above idea to a program? Let us use Input and Divisor for n and x, respectively. The following DO-loop will do the job: DO IF (MOD(Input,Divisor) /= 0 .OR. Input == 1) EXIT ... since MOD(Input,Divisor)=0 here, Divisor is a factor... Input = Input / Divisor END DO In the above, if Divisorcannot evenly divide Inputor Inputis 1, we exit the loop. The former condition states that Divisoris not a factor of Input, while the latter means Inputis 1 and does not have any other factor. If both conditions are .FALSE., then Divisor can evenly divide Input and Input is not 1. Therefore, Input is a factor of Divisor. To remove it, just perform a division and this is the meaning of Input = Input / Divisor.
Since 2 is the only even prime number, we'd better remove all factors of 2 before starting any other work. Therefore, letting Divisor to 2 in the above code will remove all factor of 2: DO IF (MOD(Input,2) /= 0 .OR. Input == 1) EXIT ... since MOD(Input,2)=0 here, 2 is a factor... Input = Input / Divisor END DO After exiting this loop, we are sure the new value of Inputwill have no factors of 2. Then, we can try all odd numbers to see some of them could be factors. To try odd numbers, it is simply the following: Divisor = 3 DO
IF (Divisor > Input) EXIT ...remove all factors of Divisor... Divisor = Divisor + 2 END DO
q q
Putting everything together, it is the program shown above. Why the factors found are prime numbers? A good question, indeed. It is not difficult to answer, however. If Input does have a composite factor (a composite number is the product of several prime numbers), say x = a*b, where a is a prime number. Then, before the program can test if x is a factor, a has been tested since a < x, and the factor a is removed. Consequently, only a possible factor b remains. In other words, composite number x is never tested and the program will not report any composite factors. Let us factorize 586390350 as an example: 1. Factors of 2 are removed first. Removing the first factor of 2 yields 293195175=586390350/2. 2. Since 293195175 is not even, it has no more factors of 2. So, we shall try all odd numbers: 3, 5, 7, 9, 11, ... 3. Removing a factor of 3 yields 97731725=293195175/3. 4. Since 97731725 has no factors of 3, try 5. 5. Removing a factor of 5 yields 19546345=97731725/5. 6. Removing a factor of 5 a second time yields 3909269=19546345/5. 7. Since 3909269 has no factors of 5, try 7. 8. Removing a factor of 7 yields 558467=3909269/7. 9. Removing a second factor of 7 yields 79781=558467/7. 10. Since 79781 has no factors of 7, try 9. 11. Since 79781 has no factors of 9, try 11. 12. Since 79781 has no factors of 11, try 13. 13. Removing a factor of 13 yields 6137=79781/13. 14. Since 6137 has no factor of 13, try 15. 15. Since 6137 has no factor of 15, try 17. 16. Removing a factor of 17 yields 361=6137/17. 17. Since 361 has no factor of 17, try 19. 18. Removing a factor of 19 yields 19=361/19. 19. Removing a second factor of 19 yields 1=19/19. 20. Since the quotient is already 1, stop and all factors have been reported. You might feel this is not a very efficient method since testing if 9 and 15 are factors are redundant. Yes, you are right; but, this is already a reasonable complicated program for CS110 and CS201. You could learn more efficient factorization algorithms in other computer science and/or mathematics courses, since this is an extremely important topic.
Examples
q
In the following code, the DO-loop keeps reading in three integer values into variables a, b and c. After executing a READ, if Reason is greater than zero, something was wrong in the input; if Reason is less than zero, end-of-file has reached. Only if Reason is zero, one can start normal processing. INTEGER :: Reason INTEGER :: a, b, c
DO READ(*,*,IOSTAT=Reason) a, b, c IF (Reason > 0) THEN ... something wrong ... ELSE IF (Reason < 0) THEN ... end of file reached ... ELSE ... do normal stuff ... END IF END DO
q
The following code keeps reading an integer at a time and adds them to a variable sum. If io is greater than zero, it displays 'Check input. Something was wrong'; if io is less than zero, it displays the value of sum. Note that both cases EXIT the DO-loop since continuing the loop execution makes no sense. Otherwise, the value of x is meaningful and is added to sum. INTEGER :: io, x, sum sum = 0 DO READ(*,*,IOSTAT=io) x IF (io > 0) THEN WRITE(*,*) 'Check input. Something was wrong' EXIT ELSE IF (io < 0) THEN WRITE(*,*) 'The total is ', sum EXIT ELSE sum = sum + x END IF END DO Now if the input is 1 3 4 the above code should display 8 (=1+3+4). If the input is 1 @ 3 since @ is not a legal integer, the second time the READis executed, iowould receive a positive number and the above program exits the DO-loop.
Since computing geometric mean requires taking root, it is further required that all input data values must be positive. As a result, this program must be able to ignore those non-positive items. However, this may cause all input items ignored. Therefore, before computing the means, this program should have one more check to see if there are valid items. Unlike a previous example, this program does not know the number of input items and must handle incorrect input data and ignore them.
Solution
! ! ! ! ! ! ! ! ! ! ----------------------------------------------------------This program can read an unknown number of input until the end of file is reached. It calculates the arithmetic, geometric, and harmonic means of these numbers. This program uses IOSTAT= to detect the following two conditions: (1) if the input contains illegal symbols (not numbers) (2) if the end of input has reached -----------------------------------------------------------
PROGRAM ComputingMeans IMPLICIT NONE REAL REAL REAL INTEGER INTEGER Sum :: :: :: :: :: X Sum, Product, InverseSum Arithmetic, Geometric, Harmonic Count, TotalValid IO ! this is new variable = 0.0
= = = =
1.0 0.0 0 0
READ(*,*,IOSTAT=IO) X ! read in data IF (IO < 0) EXIT ! IO < 0 means end-of-file reached Count = Count + 1 ! otherwise, there are data in input IF (IO > 0) THEN ! IO > 0 means something wrong WRITE(*,*) 'ERROR: something wrong in your input' WRITE(*,*) 'Try again please' ELSE ! IO = 0 means everything is normal WRITE(*,*) 'Input item ', Count, ' --> ', X IF (X <= 0.0) THEN WRITE(*,*) 'Input <= 0. Ignored' ELSE TotalValid = TotalValid + 1 Sum = Sum + X Product = Product * X InverseSum = InverseSum + 1.0/X END IF END IF END DO WRITE(*,*) IF (TotalValid > 0) THEN Arithmetic = Sum / TotalValid Geometric = Product**(1.0/TotalValid) Harmonic = TotalValid / InverseSum WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) ELSE WRITE(*,*) END IF END PROGRAM '# of items read --> '# of valid items -> 'Arithmetic mean --> 'Geometric mean --> 'Harmonic mean --> ', ', ', ', ', Count TotalValid Arithmetic Geometric Harmonic
ComputingMeans
1.0 2.0 3.0 4.0 5.0 6.0 it will generate the following output. In this input, all data values are positive and none of them is ignored. Input Input Input Input Input Input item item item item item item 1 2 3 4 5 6 --> --> --> --> --> --> 1. 2. 3. 4. 5. 6. 6 6 3.5 2.99379516 2.44897938
# of items read --> # of valid items -> Arithmetic mean --> Geometric mean --> Harmonic mean -->
q
The following input contains a few illegal items. The third one is 3.o rather than 3.0. Thus, it is not a legal real value. The eighth item is #.$, which is not a number at all. Also, the sixth and tenth are non-positive. 1.0 2.0 3.o 4.0 5.0 -1.0 7.0 #.$ 9.0 0.0 The output is shown below. It correctly identifies all illegal data input items. Input item 1 --> 1. Input item 2 --> 2. ERROR: something wrong in your input Try again please Input item 4 --> 4. Input item 5 --> 5. Input item 6 --> -1. Input <= 0. Ignored Input item 7 --> 7. ERROR: something wrong in your input Try again please Input item 9 --> 9. Input item 10 --> 0.E+0 Input <= 0. Ignored
# of items read --> # of valid items -> Arithmetic mean --> Geometric mean --> Harmonic mean -->
Discussion
q q q q
The use of IOSTAT= follows closely the examples discussed in Handling End of File: READ Statement Revisited. This program uses an INTEGER variable IO to keep track the status of a read. If the value of IO is negative, end-of-file reached and the program exists the DO-loop. If the value of IO is positive, the previous READ had some problem. A message is displayed and asks the user to try again. In an interactive environment, this is a good practice. If the value of IO is zero, we have a normal situation. Then, the program checks further to see if the input is negative. This is exactly identical to a previous example and hence its discussion is omitted.
Examples
q
The following loop only displays 1, 2, 4 and 5. If the value of i is 1, 2, 4 or 5, the execution of the loop enters the ELSE part and displays the value of i. However, if i is 3, since i == 3 is .TRUE., the CYCLE statement is executed, which brings back to the beginning of the DO-loop starting the next iteration (i.e., the iteration corresponds to i=4). INTEGER :: i DO i = 1, 5 IF (i == 3) THEN CYCLE ELSE WRITE(*,*) i END IF END DO
The following code has a DO-loop for processing the input value stored in Range. At the beginning of the loop, the value of Range is read in and checked. If the value is less than 2, the CYCLE statement brings the control back to the beginning of the loop to read a new value for Range. This will continue until a value that is greater than or equal to 2. Then, the logical expression of the IF-THEN-END IF is .FALSE. and consequently the execution continues with "... process Range ...". INTEGER :: Range DO WRITE(*,*) 'An integer >= 2 please --> ' READ(*,*) Range IF (Range < 2) THEN
WRITE(*,*) 'Input not in the required range' CYCLE END IF ... process Range ... END DO Please compare this example with the technique used in the second prime number example in which EXIT is used rather than CYCLE.
A Programming Example
This problem solves a puzzle: RED x FOR = DANGER, where each letter represents a digit and different letters means different digits. Moreover, R, F and D cannot be zero. Write a program to find all solutions.
Solution
! ! ! ! ! ! ! ! ! ---------------------------------------------------------This program solve the following puzzle: RED x FOR ------DANGER where each distinct letter represents a different digit. Moreover, R, F and D cannot be zero. ----------------------------------------------------------
PROGRAM Puzzle IMPLICIT NONE INTEGER :: R, E, D, F, O, A, N, G INTEGER :: RED, FOR, DANGER INTEGER :: Count WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) ! the digits ! the constructed values ! solutions count
'This program solves the following puzzle:' ' RED' 'x FOR' '-------' ' DANGER'
Count = 0 DO R = 1, 9 DO E = 0, 9 IF (E == R) CYCLE
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/do-cycle.html (2 of 4)8/5/2006 8:06:46 PM
DO D = 1, 9 IF (D == R .OR. D == E) CYCLE DO F = 1, 9 IF (F == R .OR. F == E .OR. F == D) CYCLE DO O = 0, 9 IF (O == R .OR. O == E .OR. O == D .OR. O == F) CYCLE DO A = 0, 9 IF (A == R .OR. A == E .OR. A == D .OR. A == F .OR. A == O) CYCLE DO N = 0, 9 IF (N == R .OR. N == E .OR. N == D .OR. N == F .OR. N == O .OR. N == A) CYCLE DO G = 0, 9 IF (G == R .OR. G == E .OR. G == D .OR. G == F .OR. G == O .OR. G == A .OR. G == N) CYCLE RED = R*100 + E*10 + D FOR = F*100 + O*10 + R DANGER = D*100000 + A*10000 + N*1000 + G*100 IF (RED * FOR == DANGER) THEN Count = Count + 1 WRITE(*,*) 'Solution ', Count, ':' WRITE(*,*) ' RED = ', RED WRITE(*,*) ' FOR = ', FOR WRITE(*,*) ' DANGER = ', DANGER WRITE(*,*) END IF END DO END DO END DO END DO END DO END DO END DO END DO END PROGRAM Puzzle
&
&
&
& &
+ E*10 + R
Program Output
The following is the output generated by the above program. There are two solutions: This program solves the following puzzle: RED FOR
------DANGER Solution RED FOR DANGER Solution RED FOR DANGER 1: = 321 = 563 = 180723 2: = 481 = 364 = 175084
Discussion
q q
This program uses a brute-force method. That is, it searches all possibilities. Since there are eight digits, R, E, D, F, O, A, N and G, each of which runs from 0 to 9 except for R, F and D which runs from 1 to 9, we need eight nested DO-loops. Since different letters represent different digits, at the very beginning of a DO-loop, we must make sure the value of its control variable is different from the values of all previous loops. DO R = 1, 9 DO E = 0, 9 IF (E == R) CYCLE DO D = 1, 9 IF (D == R .OR. D == E) CYCLE ... other loops ... END DO END DO END DO The above only shows three loops for R, E and D. At the beginning of the E loop, the value of E is checked to see if it is equal to the value of R. If they are equal, the CYCLE brings the control to the next iteration. Similarly, at the beginning of the D loop, the value of D is compared against the values of E and R. If they are equal, CYCLE causes the start of the next iteration. Note that D runs from 1 to 9. In the inner-most loop, the value of RED, FOR and DANGER are computed and compared. If RED*FOR is equal to DANGER, a solution is found and its values are displayed. RED = R*100 + E*10 + D FOR = F*100 + O*10 + R DANGER = D*100000 + A*10000 + N*1000 + G*100 + E*10 + R IF (RED * FOR == DANGER) THEN ... display READ, FOR and DANGER ... END IF
The concept of this program, except for the use of CYCLE, is similar to that of finding all three-digit Armstrong Numbers. Please compare these two programs.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/funct-module.html8/5/2006 8:09:53 PM
Designing Functions
Designing Functions
Syntax
In addition to intrinsic functions, Fortran allows you to design your own functions. A Fortran function, or more precisely, a Fortran function subprogram, has the following syntax: type FUNCTION function-name (arg1, arg2, ..., argn) IMPLICIT NONE [specification part] [execution part] [subprogram part] END FUNCTION function-name Here are some elaborations of the above syntax:
q
The first line of a function starts with the keyword FUNCTION. Before FUNCTION, the type gives the type of the function value (i.e., INTEGER, REAL, LOGICAL and CHARACTER) and after FUNCTION is the name you assign to that function. Following the function-name, there is a pair of parenthesis in which a number of arguments arg1, arg2, ..., argn are separated with commas. These arguments are referred to as formal arguments. Formal arguments must be variable names and cannot be expressions. Here are a examples: 1. The following is a function called Factorial. It takes only one formal argument n and returns an INTEGER as its function value. INTEGER FUNCTION Factorial(n)
2. The following is a function called TestSomething. It takes three formal arguments a, b and c, and returns a LOGICAL value (i.e., .TRUE. or .FALSE.) as its function value. LOGICAL FUNCTION
q q
TestSomething(a, b, c)
A function must be ended with END FUNCTION followed by the name of that function. Between FUNCTION and END FUNCTION, there are the IMPLICIT NONE, specification part, execution part and subprogram part. These are exactly identical to that of a PROGRAM.
If a function does not need any formal argument, it can be written as type FUNCTION function-name () IMPLICIT NONE [specification part] [execution part] [subprogram part] END FUNCTION function-name
Designing Functions
where arg1, arg2, ..., argn are left out. But, the pait of parenthesis must be there.
Semantics
The meaning of a function is very simple:
q
A function is a self-contained unit that receives some "input" from the outside world via its formal arguments, does some computations, and then returns the result with the name of the function. Thus, since the function returns its result via the name of the function, somewhere in the function there must exist one or more assignment statements like the following: function-name = expression where the result of expressionis stored to the name of the function. However, the name of the function cannot appear in the right-hand side of any expression. That is, the name of the function, used as a variable name, can only appear in the left-hand side of an expression. This is an artificial restriction in this course only.
A function receives its input values from formal arguments, does computations, and saves the result in its name. When the control of execution reaches END FUNCTION, the value stored in the name of the function is returned as the function value. To tell the function about the types of its formal arguments, all arguments must be declared with a new attribute INTENT(IN). The meaning of INTENT(IN) indicates that the function will only take the value from the formal argument and must not change its content. Any statements that can be used in PROGRAM can also be used in a FUNCTION.
Function Examples
Functions Examples
Here are a few examples of functions:
q
The following function has a name Sum and three formal arguments a, b and c. It returns an INTEGER function value. The INTEGER, INTENT(IN) part indicates that the function takes its input value from its three formal argument. Then, the function uses the value of these formal arguments to compute the sum and stores in Sum, the name of the function. Since the next statement is END FUNCTION, the function returns the value stored in Sum. INTEGER FUNCTION Sum(a, b, c) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b, c Sum = a + b + c END FUNCTION Sum If the value supplied to a, band care 3, 5, and -2, respectively, Sumwill receive 6 (=3+5+(-2)) and the function returns 6. The following function has a name Positive with a REAL formal argument. If the argument is positive, the function returns .TRUE.; otherwise, the function returns .FALSE. LOGICAL FUNCTION Positive(a) IMPLICIT NONE REAL, INTENT(IN) :: a IF (a > 0.0) THEN Positive = .TRUE. ELSE Positive = .FALSE. END IF END FUNCTION Positive The above function can be made much shorter by using LOGICALassignment. In the following, if a > 0.0is true, . TRUE.is stored to Positive; otherwise, Positivereceives .FALSE. LOGICAL FUNCTION Positive(a) IMPLICIT NONE REAL, INTENT(IN) :: a Positive = a > 0.0 END FUNCTION Positive
The following function, LargerRoot, takes three REAL formal arguments and returns a REAL function value. It
Function Examples
returns the larger root of a quadratic equation ax2 + bx + c = 0. REAL FUNCTION LargerRoot(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a REAL, INTENT(IN) :: b REAL, INTENT(IN) :: c REAL :: d, r1, r2 = SQRT(b*b - 4.0*a*c) = (-b + d) / (2.0*a) = (-b - d) / (2.0*a) (r1 >= r2) THEN LargerRoot = r1 ELSE LargerRoot = r2 END IF END FUNCTION LargerRoot The above example shows that you can declare other variables such as d, r1and r2if they are needed. The following function, Factorial(), has only one INTEGER formal argument n >= 0, and computes and returns the factorial of n, n!. INTEGER FUNCTION Factorial(n) IMPLICIT NONE INTEGER, INTENT(IN) :: n INTEGER :: i, Ans Ans = 1 DO i = 1, n Ans = Ans * i END DO Factorial = Ans END FUNCTION Note that the function name Factorialis not used in any computation. Instead, a new INTEGERvariable is used for computing n!. The final value of Ansis stored to Factorialbefore leaving the function. If Factorial is involved in computation like the following: INTEGER FUNCTION Factorial(n) IMPLICIT NONE INTEGER, INTENT(IN) :: n INTEGER :: i Factorial = 1 DO i = 1, n
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/f-examp.html (2 of 3)8/5/2006 8:09:59 PM
d r1 r2 IF
Function Examples
Factorial = Factorial * i END DO END FUNCTION then there is a mistake although the above program looks normal. The reason is that the function name cannot appear in the right-hand sidein any expression of that function. The following function GetNumber() does not have any formal arguments and returns an INTEGER function value. This function has a DO-loop which keeps asking the user to input a positive number. The input is read into the function name. If this value is positive, then EXIT and the function returns the value in GetNumber. Otherwise, the loop goes back and asks the user again for a new input value. REAL FUNCTION GetNumber() IMPLICIT NONE DO WRITE(*,*) 'A positive real number --> ' READ(*,*) GetNumber IF (GetNumber > 0.0) EXIT WRITE(*,*) 'ERROR. Please try again.' END DO WRITE(*,*) END FUNCTION GetNumber
Common Problems
Common Problems
q
Forget the type of a FUNCTION. FUNCTION DoSomething(a, b) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b DoSomthing = SQRT(a*a + b*b) END FUNCTION DoSomthing If there is no type, you will not be able to determine if the returned value is an INTEGER, a REALor something else. Forget INTENT(IN). REAL FUNCTION DoSomething(a, b) IMPLICIT NONE INTEGER :: a, b DoSomthing = SQRT(a*a + b*b) END FUNCTION DoSomthing Actually, this is notan error. But, without INTENT(IN), our Fortran compiler will not be able to check many potential errors for you. Change the value of a formal argument declared with INTENT(IN). REAL FUNCTION DoSomething(a, b) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b IF (a > b) a = a ELSE a = a + END IF DoSomthing END FUNCTION THEN b b = SQRT(a*a + b*b) DoSomthing
Since formal argument ais declared with INTENT(IN), its value cannot be changed. Forget to store a value to the function name. REAL FUNCTION DoSomething(a, b) IMPLICIT NONE
Common Problems
INTEGER, INTENT(IN) :: a, b INTEGER :: c c = SQRT(a*a + b*b) END FUNCTION DoSomthing When the execution of this function reaches END FUNCTION, it returns the value stored in DoSomething. However, in the above, since there is no value ever stored in DoSmething, the returned value could be anything (i.e., a garbage value). Function name is used in the right-hand side of an expression. REAL FUNCTION DoSomething(a, b) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b DoSomething = a*a + b*b DoSomething = SQRT(DoSomething) END FUNCTION DoSomthing In the above, function name DoSomethingappears in the right-hand side of the second expression. This is a mistake. Only a special type of functions, RECURSIVEfunctions, could have their names in the right-hand side of expressions. Only the most recent value stored in the function name will be returned.. REAL FUNCTION DoSomething(a, b) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b DoSomething = a*a + b*b DoSomething = SQRT(a*a - b*b) END FUNCTION DoSomthing In the above, the value of SQRT(a*a-b*b)rather than the value of a*a + b*bis returned. In fact, this is obvious. Since the name of a function can be considered as a special variable name, the second assignment overwrites the previous value.
Using Functions
Using Functions
The way of using a user-defined function is exactly identical to that of using Fortran intrinsic functions. One can use a function in an expression and in a WRITE. Suppose we have the following function: REAL FUNCTION Average(x, y, z) IMPLICIT NONE REAL, INTENT(IN) :: x, y, z Average = (x + y + z) / 3.0 END FUNCTION Average This function takes three REAL formal arguments and returns their average. To use this function, one needs to supply values to the formal arguments. For example, one could write the following: ..... = ..... + Average(1.0, 2.0, 3.0) * .....
The above expression involves the use of function Average. Since this function has three formal arguments, three values must be presented to the function. Here, the values are 1.0, 2.0 and 3.0 and the returned value is the average of these three numbers (i.e., 2.0). The values or expressions used to invoke a function are referred to as actual arguments. Please keep the following important rules in mind:
q
The number of formal arguments and actual arguments must be equal. ..... = ... + Average(1.0, 2.0, 3.0, 4.0) * .... ..... = ... - Average(3.0, 6.0) + ..... The first line has more actual arguments than the number of formal arguments, and the second line has less actual arguments than the number of formal arguments. The type of the corresponding actual and formal arguments must be identical. WRITE(*,*) Average(1, 2.5, 3.7) In the above example, the first actual argument is an INTEGERwhich doe not match with the type of the first formal argument. Thus, it is incorrect. The actual arguments can be constants, variables and even expressions. REAL :: a = 1.0, b = 2.0, c = 3.0 ..... = ... + Average(1.0, 2.0, 3.0) + ..... ..... = ... + Average(a, b, c) + ..... ..... = ... + Average(a+b, b*c, (b+c)/a) + .....
Using Functions
In the above, the first line shows the use of constants as actual arguments. The second line uses variables, while the third uses expression. In the third line, the result of evaluating a+b, b*cand (b+c)/awill be supplied to the three formal arguments of function Average(). Please continue with the next page on argument association
Argument Association
Argument Association
When using a function, the values of actual arguments are passed to their corresponding formal arguments. There are some important rules:
q
q q
If an actual argument is an expression, it is evaluated and the result is saved into a temporary location. Then, the value in this temporary location is passed. If an actual argument is a constant, it is considered as an expression. Therefore, its value is saved to a temporary location and then passed. If an actual argument is a variable, its value is taken and passed to the corresponding formal argument. If an actual argument is a variable enclosed in a pair of parenthesis like (A), then this is an expression and its value is evaluated and saved to a temporary location. Then, this value (in the temporary location) is passed. For a formal argument declared with INTENT(IN), any attempt to change its value in the function will cause a compiler error. The meaning of INTENT(IN) is that this formal argument only receives a value from its corresponding actual argument and its value cannot be changed. Based on the previous point, if a formal argument is declared without using INTENT(IN), its value can be changed. For writing functions, this is not a good practice and consequently all formal arguments should be declared with INTENT(IN).
Example
We shall use the following function to illustrate the above rules. Function Small() takes three formal arguments x, y and z and returns the value of the smallest. INTEGER :: a, b, c a = 10 b = 5 c = 13 WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) INTEGER FUNCTION Small(x, y, z) IMPLICIT NONE INTEGER, INTENT(IN) :: x, y, z .AND. x <= z) THEN x <= x .AND. y <= z) THEN y z Small
IF (x <= y Small(a,b,c) Small = Small(a+b,b+c,c) ELSE IF (y Small(1, 5, 3) Small = Small((a),(b),(c)) ELSE Small = END IF END FUNCTION
In the first WRITE, all three arguments are variable and their values are sent to the corresponding formal argument. Therefore, x, y and z in function Small() receives 10, 5 and 13, respectively. The following diagram illustrate this association:
Argument Association
In the second WRITE, the first and second arguments are expression a+b, b+c. Thus, they are evaluated yielding 15 and 18. These two values are saved in two temporary locations and passed to function Small() along with variable c. Thus, x, y and z receive 15, 18 and 13 respectively. This is illustrated as follows. In the figure, squares drawn with dotted lines are temperary locations that are created for passing the values of arguments.
In the third WRITE, since all actual arguments are constants, their values are "evaluated" to temporary locations and then sent to x, y and z.
In the fourth WRITE, since all three actual arguments are expressions, they are evaluated and stored in temporary locations. Then, these values are passed to x, y and z.
Argument Association
Thus, x, y and z receive 10, 5 and 13, respectively. Note that while the formal arguments of function Small() receive the same values using the first and the fourth lines, the argument associations are totally different. The first line has the values in variables passed directly and the the fourth line evaluates the expressions into temporary locations whose values are passed. This way of argument association does not have impact on functions (since you must use INTENT(IN)), it will play an important role in subroutine subprograms.
Examples
q
The following complete program "contains" one function, Average(). The execution part consists of three statements, a READ, an assignment and a WRITE. These three statements must be placed before the keyword CONTAINS. Note also that END PROGRAM must be the last line of your program. PROGRAM Avg IMPLICIT NONE REAL :: a, b, c, Mean READ(*,*) a, b, c Mean = Average(a, b, c) WRITE(*,*) a, b, c, Mean CONTAINS REAL FUNCTION Average(a, b, c) IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c Average = (a + b + c) / 3.0 END FUNCTION Average END PROGRAM Avg
q
The following program "contains" two functions Large() and GeoMean(). The order of these functions are unimportant. PROGRAM TwoFunctions IMPLICIT NONE INTEGER :: a, b, BiggerOne REAL :: GeometricMean READ(*,*) a, b BiggerOne = Large(a,b) GeometricMean = GeoMean(a,b) WRITE(*,*) 'Input = ', a, b WRITE(*,*) 'Larger one = ', BiggerOne WRITE(*,*) 'Geometric Mean = ', GeometricMean CONTAINS INTEGER FUNCTION Large(a, b) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b IF (a >= b) THEN Large = a ELSE Large = b END IF END FUNCTION Large REAL FUNCTION GeoMean(a, b) IMPLICIT NONE INTEGER, INTENT(IN) :: a, b GeoMean = SQRT(REAL(a*b)) END FUNCTION GeoMean END PROGRAM TwoFunctions
A Important Note
Although in general a function can "contain" other functions, an internal function CANNOT contain any other functions.
In the following example, the main program "contains" an internal function InternalFunction(), which in turn contains another internal function Funct(). This is incorrect, since an internal function cannot contain another internal function. In other words, the internal functions of a main program must be on the same level. PROGRAM Wrong IMPLICIT NONE ......... CONTAINS INTEGER FUNCTION InternalFunction(.....) IMPLICIT NONE ........ CONTAINS REAL FUNCTION Funct(.....) IMPLICIT NONE ........ END FUNCTION Funct END FUNCTION InternalFunction END PROGRAM Wrong Please continue with the next important topic about scope rules.
Scope Rules
Scope Rules
Since a main program could contain many functions and in fact a function can contain other functions (i.e., nested functions), one may ask the following questions: 1. Could a function use a variable declared in the main program? 2. Could a main program use a variable declared in one of its function? The scope rules answer these questions. In fact, scope rules tell us if an entity (i.e., variable, parameter and function) is "visible" or accessible at certain places. Thus, places where an entity can be accessed or visible is referred to the scope of that entity. The simplest rule is the following: Scope Rule 1 The scope of an entity is the program or function in which it is declared.
Therefore, in the following, the scope of parameter PI and variables m and n is the main program, the scope of formal argument k and REAL variables f and g is function Funct1(), and the scope of formal arguments u and v is function Funct2 (). PROGRAM Scope_1 IMPLICIT NONE REAL, PARAMETER :: PI = 3.1415926 INTEGER :: m, n ................... CONTAINS INTEGER FUNCTION Funct1(k) IMPLICIT NONE INTEGER, INTENT(IN) :: k REAL :: f, g .......... END FUNCTION Funct1 REAL FUNCTION Funct2(u, v) IMPLICIT NONE REAL, INTENT(IN) :: u, v .......... END FUNCTION Funct2 END PROGRAM Scope_1 There is a direct consequence of Scope Rule 1. Since an entity declared in a function has a scope of that function, this entity cannot be seen from outside of the function. In the above example, formal argument k and variables f and g are declared within function Funct1(), they are only "visible" in function Funct1() and are not visible outside of Funct1(). In other words, since k, f and g are not "visible" from the main program and function Funct2(), they cannot be used in the main
Scope Rules
program and function Funct2(). Similarly, the main program and function Funct1() cannot use the formal arguments u and v and any entity declared in function Funct2().
Local Entities
Due to the above discussion, the entities declared in a function or in the main program are said local to that function or the main program. Thus, k, f and g are local to function Funct1(), u and v are local to function Funct2(), and PI, m and n are local to the main program.
Global Entities
Given a function f(), entities that are declared in all containing functions or the main program are said global to f(). In the above example, since variables m and n are declared in the main program, they are global to Funct1() and function Funct2 (). However, variables f and g are not global to function Funct2(), since Funct1() does not contain Funct2(). Similarly, formal arguments u and v are not global to function Funct1(). This comes the second scope rule: A global entity is visible to all contained functions, including the function in which that entity is declared.
Scope Rule 2
Continue with the above example, since m and n are global to both functions Funct1() and Funct2(), they can be used in these two functions. PROGRAM Scope_2 IMPLICIT NONE INTEGER :: a = 1, b = 2, c = 3 WRITE(*,*) c = 4 WRITE(*,*) WRITE(*,*) Add(a) Add(a) Mul(b,c)
CONTAINS INTEGER FUNCTION Add(q) IMPLICIT NONE INTEGER, INTENT(IN) :: q Add = q + c END FUNCTION Add INTEGER FUNCTION Mul(x, y) IMPLICIT NONE INTEGER, INTENT(IN) :: x, y Mul = x * y END FUNCTION Mul END PROGRAM Scope_2
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/scope.html (2 of 4)8/5/2006 8:10:12 PM
Scope Rules
In the above program, variables a, b and c are global to both functions Add() and Mul(). Therefore, since variable c used in function Add() is global to Add(), expression q + c means computing the sum of the value of the formal argument q and the value of global variable c. Therefore, the first WRITE produces 4 (= 1 + 3). Before the second WRITE, the value of c is changed to 4 in the main program. Hence, the second WRITE produces 5 (= 1 + 4). The third WRITE produces 8 (= 2 * 4). Thus, the first two WRITEs produce different results even though their actual arguments are the same! This is usually refereed to as a side effect. Therefore, if it is possible, avoid using global variables in internal functions. Let us continue with the above example. To remove side effect, one could add one more argument to function Add() for passing the value of c. PROGRAM Scope_2 IMPLICIT NONE INTEGER :: a = 1, b = 2, c = 3 WRITE(*,*) c = 4 WRITE(*,*) WRITE(*,*) Add(a, c) Add(a, c) Mul(b,c)
CONTAINS INTEGER FUNCTION Add(q, h) IMPLICIT NONE INTEGER, INTENT(IN) :: q, h Add = q + h END FUNCTION Add INTEGER FUNCTION Mul(x, y) IMPLICIT NONE INTEGER, INTENT(IN) :: x, y Mul = x * y END FUNCTION Mul END PROGRAM Scope_2
In the program below, the main program declares a variable i, which is global to function Sum(). However, i is also declared in function Sum(). According to Scope Rule 3 above, these two is are two different entities. More precisely, when the value of Sum()'s i is changed, this change will not affect the i in the main program and vice versa. This would save us a lot of time in finding variables with different names.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/scope.html (3 of 4)8/5/2006 8:10:12 PM
Scope Rules
PROGRAM Scope_3 IMPLICIT NONE INTEGER :: i, Max = 5 DO i = 1, Max Write(*,*) END DO CONTAINS INTEGER FUNCTION Sum(n) IMPLICIT NONE INTEGER, INTENT(IN) :: n INTEGER :: i, s s = 0 DO i = 1, n s = s + i END DO Sum = s END FUNCTION Sum END PROGRAM Scope_3
Sum(i)
Commuting Cubes
Computing Cubes
Problem Statement
Write a program to compute the cubes of 1, 2, 3, ..., 10 in both INTEGER and REAL types. It is required to write a function intCube() for computing the cube of an integer and a function realCube() for computing the cube of a real.
Solution
! ! ! ! ! ----------------------------------------------------This program display the cubes of INTEGERs and REALs. The cubes are computed with two functions: intCube() and realCube(). -----------------------------------------------------
PROGRAM Cubes IMPLICIT NONE INTEGER, PARAMETER :: Iterations = 10 INTEGER :: i REAL :: x DO i = 1, Iterations x = i WRITE(*,*) i, x, intCube(i), realCube(x) END DO CONTAINS ! ----------------------------------------------------! INTEGER FUNCTION intCube() : ! This function returns the cube of the argument. ! ----------------------------------------------------INTEGER FUNCTION intCube(Number) IMPLICIT NONE INTEGER, INTENT(IN) :: Number intCube = Number*Number*Number END FUNCTION intCube ! ----------------------------------------------------! REAL FUNCTION realCube() : ! This function returns the cube of the argument. ! ----------------------------------------------------http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/cube.html (1 of 2)8/5/2006 8:10:13 PM
Commuting Cubes
REAL FUNCTION realCube(Number) IMPLICIT NONE REAL, INTENT(IN) :: Number realCube = Number*Number*Number END FUNCTION realCube END PROGRAM Cubes
Discussion
q q
Functions intCube() and realCube() are identical except for the types of formal arguments and returned values. The main program has a DO-loop that iterates Iterations times (this is a PARAMETER, or an alias, of 10). Variable x holds the real value of integer variable i.
Write a program to read three positive numbers and use three functions to compute the arithmetic, geometric and harmonic means.
Solution
! ---------------------------------------------------------! This program contains three functions for computing the ! arithmetic, geometric and harmonic means of three REALs. ! ---------------------------------------------------------PROGRAM ComputingMeans IMPLICIT NONE REAL :: a, b, c a, b, c 'Input: ', a, b, c 'Arithmetic mean = ', ArithMean(a, b, c) 'Geometric mean = ', GeoMean(a, b, c) 'Harmonic mean = ', HarmonMean(a, b, c)
---------------------------------------------------------REAL FUNCTION ArithMean() : This function computes the arithmetic mean of its three REAL arguments. ---------------------------------------------------------REAL FUNCTION ArithMean(a, b, c)
IMPLICIT
NONE
REAL, INTENT(IN) :: a, b, c ArithMean = (a + b + c) /3.0 END FUNCTION ArithMean ! ! ! ! ! ---------------------------------------------------------REAL FUNCTION GeoMean() : This function computes the geometric mean of its three REAL arguments. ---------------------------------------------------------REAL FUNCTION GeoMean(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c GeoMean = (a * b * c)**(1.0/3.0) END FUNCTION GeoMean ! ! ! ! ! ---------------------------------------------------------REAL FUNCTION HarmonMean() : This function computes the harmonic mean of its three REAL arguments. ---------------------------------------------------------REAL FUNCTION HarmonMean(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c HarmonMean = 3.0 / (1.0/a + 1.0/b + 1.0/c) END FUNCTION HarmonMean END PROGRAM ComputingMeans
Discussion
q q
Each of these functions is simple and does not require further explanation. Note that the main program and all three functions use the same names a, b and c. By Scope Rule 3, they are all different entities. That is, when function ArithMean() is using a, it is using its own local formal argument rather than the global variable a declared in the main program.
Solution
! ! ! ! ! ! ! ! ! ! --------------------------------------------------------------This program "contains" two REAL functions: (1) Cm_to_Inch() takes a real inch unit and converts it to cm unit, and (2) Inch_to_cm() takes a real cm unit and converts it to inch unit. The main program uses these functions to convert 0, 0.5, 1, 1.5, 2.0, 2.5, ..., 8.0, 8.5, 9.0, 9.5 and 10.0 inch (resp., cm) to cm (resp., inch). ---------------------------------------------------------------
PROGRAM Conversion IMPLICIT NONE REAL, PARAMETER :: Initial = 0.0, Final = 10.0, Step = 0.5 REAL :: x x = Initial DO ! x = 0, 0.5, 1.0, ..., 9.0, 9.5, 10 IF (x > Final) EXIT WRITE(*,*) x, 'cm = ', Cm_to_Inch(x), 'inch and ', & x, 'inch = ', Inch_to_Cm(x), 'cm' x = x + Step END DO CONTAINS ! --------------------------------------------------------------! REAL FUNCTION Cm_to_Inch() ! This function converts its real input in cm to inch. ! --------------------------------------------------------------REAL FUNCTION Cm_to_Inch(cm) IMPLICIT NONE REAL, INTENT(IN) :: cm REAL, PARAMETER :: To_Inch = 0.3937
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/convert.html (1 of 3)8/5/2006 8:10:18 PM
! conversion factor
Cm_to_Inch = To_Inch * cm END FUNCTION Cm_to_Inch ! --------------------------------------------------------------! REAL FUNCTION Inch_to_Cm() ! This function converts its real input in inch to cm. ! --------------------------------------------------------------REAL FUNCTION Inch_to_Cm(inch) IMPLICIT NONE REAL, INTENT(IN) :: inch REAL, PARAMETER :: To_Cm = 2.54 Inch_to_Cm = To_Cm * inch END FUNCTION Inch_to_Cm END PROGRAM Conversion
! conversion factor
Discussion
q
Function Cm_to_Inch() converts its formal argument cm to inch, which is returned as the function value. Please note that the constant 0.3937 is defined as a PARAMETER. Function Inch_to_Cm() converts its formal argument inch to cm, which is returned as the function value. Please note that the constant 2.54 is defined as a PARAMETER. The main program uses DO-EXIT-END DO to generate 0, 0.5, 1, 1.5, ..., 8, 8.5, 9, 9.5 and 10. For each value, Cm_to_Inch() and Inch_to_Cm() are called to perform the desired conversion.
In order for a, b and c to form a triangle, two conditions must be satisfied. First, all side lengths must be positive:
Second, the sum of any two side lengths must be greater than the third side length:
Write a program to read in three real values and use a function for testing the conditions and another function for computing the area. Should the conditions fail, your program must keep asking the user to re-enter the input until the input form a triangle. Then, the other function is used to compute the area.
Solution
! -------------------------------------------------------------------! This program uses Heron's formula to compute the area of a ! triangle. It "contains" the following functions; ! (1) LOGICAL function TriangleTest() ! this function has three real formal arguments and tests ! to see if they can form a triangle. If they do form a ! triangle, this function returns .TRUE.; otherwise, it ! returns .FALSE. ! (2) REAL function TriangleArea() ! this functions has three real formal arguments considered ! as three sides of a triangle and returns the area of this ! triangle. ! -------------------------------------------------------------------http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/area-2.html (1 of 3)8/5/2006 8:10:21 PM
PROGRAM HeronFormula IMPLICIT NONE REAL :: a, b, c, TriangleArea DO WRITE(*,*) 'Three sides of a triangle please --> ' READ(*,*) a, b, c WRITE(*,*) 'Input sides are ', a, b, c IF (TriangleTest(a, b, c)) EXIT ! exit if not a triangle WRITE(*,*) 'Your input CANNOT form a triangle. Try again' END DO TriangleArea = Area(a, b, c) WRITE(*,*) 'Triangle area is ', TriangleArea CONTAINS ! ! ! ! ! ! ! ! ! -------------------------------------------------------------------LOGICAL FUNCTION TriangleTest() : This function receives three REAL numbers and tests if they form a triangle by testing: (1) all arguments must be positive, and (2) the sum of any two is greater than the third If the arguments form a triangle, this function returns .TRUE.; otherwise, it returns .FALSE. -------------------------------------------------------------------LOGICAL FUNCTION TriangleTest(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c LOGICAL :: test1, test2 test1 = (a > 0.0) .AND. (b > 0.0) .AND. (c > 0.0) test2 = (a + b > c) .AND. (a + c > b) .AND. (b + c > a) TriangleTest = test1 .AND. test2 ! both must be .TRUE. END FUNCTION TriangleTest ! ! ! ! ! -------------------------------------------------------------------REAL FUNCTION Area() : This function takes three real number that form a triangle, and computes and returns the area of this triangle using Heron's formula. -------------------------------------------------------------------REAL FUNCTION Area(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c REAL :: s
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/area-2.html (2 of 3)8/5/2006 8:10:21 PM
Discussion
q
LOGICAL function TriangleTest() receives three REAL values. The result of the first test condition is saved to a local LOGICAL variable test1, while the result of the second condition is saved to another LOGICAL variable test2. Since both conditions must be true to have a triangle, test1 and test2 are .AND.ed and the result goes into the function name so that it could be returned. REAL function Area is simple and does not require further discussion. However, please note that Area() has three formal arguments whose names are identical to the three global variables declared in the main program. By Scope Rule 3, they are different entities and do not cause any conflicts. The main program has a DO-EXIT-END DO loop. In each iteration, it asks for three real values. These values are sent to LOGICAL function TriangleTest() for testing. If the returned value is .TRUE., the input form a triangle and the control of execution exits. Then, the area is computed with REAL function Area(). If the returned value is . FALSE., this function displays a message and goes back asking for a new set of values.
where 0 <= r <= n must hold. Write a program that keeps reading in values for n and r, exits if both values are zeros, uses a LOGICAL function to test if 0 <= r <= n holds, and computes C(n,r) with an INTEGER function.
Solution
! ! ! ! ! ! ! ! ! ! ! ! ! ! --------------------------------------------------------------This program computes the combinatorial coefficient C(n,r): n! C(n,r) = ------------r! x (n-r)! It asks for two integers and uses Cnr(n,r) to compute the value. If 0 <= r <= n does not hold, Cnr() returns -1 so that the main program would know the input values are incorrect. Otherwise, Cnr() returns the desired combinatorial coefficient. Note that if the input values are zeros, this program stops. ---------------------------------------------------------------
PROGRAM Combinatorial IMPLICIT NONE INTEGER :: n, r, Answer DO WRITE(*,*) WRITE(*,*) "Two integers n and r (0 <= r <= n) please " WRITE(*,*) "0 0 to stop --> " READ(*,*) n, r IF (n == 0 .AND. r == 0) EXIT WRITE(*,*) "Your input:" WRITE(*,*) " n = ", n WRITE(*,*) " r = ", r Answer = Cnr(n, r)
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/cnr-1.html (1 of 4)8/5/2006 8:10:24 PM
IF (Answer < 0) THEN WRITE(*,*) "Incorrect input" ELSE WRITE(*,*) " C(n,r) = ", Answer END IF END DO CONTAINS ! ! ! ! ! ! --------------------------------------------------------------INTEGER FUNCTION Cnr(n,r) This function receives n and r, uses LOGICAL function Test() to verify if the condition 0 <= r <= n holds, and uses Factorial() to compute n!, r! and (n-r)!. --------------------------------------------------------------INTEGER FUNCTION Cnr(n, r) IMPLICIT NONE INTEGER, INTENT(IN) :: n, r IF (Test(n,r)) THEN Cnr = Factorial(n)/(Factorial(r)*Factorial(n-r)) ELSE Cnr = -1 END IF END FUNCTION Cnr ! ! ! ! ! --------------------------------------------------------------LOGICAL FUNCTION Test() This function receives n and r. If 0 <= r <= n holds, it returns .TRUE.; otherwise, it returns .FALSE. --------------------------------------------------------------LOGICAL FUNCTION Test(n, r) IMPLICIT NONE INTEGER, INTENT(IN) :: n, r Test = (0 <= r) .AND. (r <= n) END FUNCTION Test ! ! ! ! ! --------------------------------------------------------------INTEGER FUNCTION Factorial() This function receives a non-negative integer and computes its factorial. --------------------------------------------------------------INTEGER FUNCTION Factorial(k) IMPLICIT NONE INTEGER, INTENT(IN) :: k INTEGER :: Ans, i
Ans = 1 DO i = 1, k Ans = Ans * i END DO Factorial = Ans END FUNCTION Factorial END PROGRAM Combinatorial
In the sample output above, please note the error messages indicating that condition 0 <= r <= n does not hold. Please also note that the program stops when the input values are 0 and 0.
Discussion
q
q q
The function that computes the combinatorial coefficient is INTEGER function Cnr(n,r). Since it must compute n!, r! and (n-r)!, it would be better to write a function to compute the factorial of an integer. In this way, Cnr() would just use Factorial() three times rather than using three DO-loops. Note that if the condition does not hold, Cnr() returns -1. INTEGER function Factorial() computes the factorial of its formal argument. LOGICAL function Test() is very simple. If condition 0 <= r <= n holds, Test receives .TRUE.; otherwise, it receives .FALSE. The main program has a DO-EXIT-END DO. It asks for two integers and indicates that the program will stop if both values are zeros. Then, Cnr() is used for computing the combinatorial coefficient. If the returned value is negative, the input values do not meet the condition and an error message is displayed. Otherwise, the combinatorial coefficient is shown. Note that all three functions are internal functions of the main program.
One can start with b as a rough guess and compute New x; from New x, one can generate a even better guess, until two successive guesses are very close. Either one could be considered as the square root of b. Write a function MySqrt() that accepts a formal argument and uses Newton's method to computes its square root. Then, write a main program that reads in an initial value, a final value, and a step size, and computes the square roots of these successive values with Newton'e method and Fortran's SQRT() function, and determines the absolute error.
Solution
! ! ! ! ! ! ! --------------------------------------------------------------This program contains a function MySqrt() that uses Newton's method to find the square root of a positive number. This is an iterative method and the program keeps generating better approximation of the square root until two successive approximations have a distance less than the specified tolerance. ---------------------------------------------------------------
PROGRAM SquareRoot IMPLICIT NONE REAL REAL :: Begin, End, Step :: x, SQRTx, MySQRTx, Error
READ(*,*) Begin, End, Step ! read in init, final and step x = Begin ! x starts with the init value DO IF (x > End) EXIT ! exit if x > the final value SQRTx = SQRT(x) ! find square root with SQRT() MySQRTx = MySqrt(x) ! do the same with my sqrt() Error = ABS(SQRTx - MySQRTx) ! compute the absolute error WRITE(*,*) x, SQRTx, MySQRTx, Error ! display the results x = x + Step ! move on to the next value END DO
CONTAINS ! ! ! ! ! ! ! ! --------------------------------------------------------------REAL FUNCTION MySqrt() This function uses Newton's method to compute an approximate of a positive number. If the input value is zero, then zero is returned immediately. For convenience, the absolute value of the input is used rather than kill the program when the input is negative. --------------------------------------------------------------REAL FUNCTION MySqrt(Input) IMPLICIT NONE REAL, INTENT(IN) :: Input REAL :: X, NewX REAL, PARAMETER :: Tolerance = 0.00001 IF (Input == 0.0) THEN ! if the input is zero MySqrt = 0.0 ! returns zero ELSE ! otherwise, X = ABS(Input) ! use absolute value DO ! for each iteration NewX = 0.5*(X + Input/X) ! compute a new approximation IF (ABS(X - NewX) < Tolerance) EXIT ! if very close, exit X = NewX ! otherwise, keep the new one END DO MySqrt = NewX END IF END FUNCTION MySqrt END PROGRAM SquareRoot
2.44948983, 2.44948959, 2.384185791E-7 2.54950976, 2.54950976, 0.E+0 2.64575124, 2.64575148, 2.384185791E-7 2.73861289, 2.73861265, 2.384185791E-7 2.82842708, 2.82842708, 0.E+0 2.91547585, 2.91547585, 0.E+0 3., 3., 0.E+0 3.08220696, 3.08220696, 0.E+0 3.1622777, 3.1622777, 0.E+0
Discussion
This program has nothing special. Please refer to the discussion of Newton's method for the computation details of function MySqrt(). However, there is one thing worth to be mentioned. Since the formal argument Input is declared with INTENT (IN), it cannot be changed in function MySqrt(). Therefore, the value of the formal argument Input is copied to X and used in square root computation.
Solution
! ! ! ! ! ! ! ! ! ! ! --------------------------------------------------------This program computes the GCD of two positive integers using the Euclid method. Given a and b, a >= b, the Euclid method goes as follows: (1) dividing a by b yields a reminder c; (2) if c is zero, b is the GCD; (3) if c is no zero, b becomes a and c becomes c and go back to Step (1). This process will continue until c is zero. Euclid's algorithm is implemented as an INTEGER function GCD(). ---------------------------------------------------------
WRITE(*,*) 'Two positive integers please --> ' READ(*,*) a, b WRITE(*,*) 'The GCD of is ', GCD(a, b) CONTAINS ! ! ! ! ! --------------------------------------------------------INTEGER FUNCTION GCD(): This function receives two INTEGER arguments and computes their GCD. --------------------------------------------------------INTEGER FUNCTION GCD(x, y) IMPLICIT NONE INTEGER, INTENT(IN) :: x, y INTEGER :: a, b, c a = x ! we need x and y here
b = y IF (a <= b) THEN c = a a = b b = c END IF DO c = MOD(a, b) IF (c == 0) EXIT a = b b = c END DO GCD = b END FUNCTION END PROGRAM
! ! ! !
since x and y are declared with INTENT(IN), they cannot be involved in this swapping process. So, a, b and c are used instead.
GCD
GreatestCommonDivisor
Discussion
Nothing special is here. As in the previous example, since x and y are declared with INTENT(IN), their values cannot be modified and therefore their values are copies to a and b to be used in other computation.
Solution
! ! ! ! -------------------------------------------------------------------This program finds all prime numbers in the range of 2 and an input integer. --------------------------------------------------------------------
Range = GetNumber() Count = 1 ! input is correct. start counting WRITE(*,*) ! since 2 is a prime WRITE(*,*) 'Prime number #', Count, ': ', 2 DO Number = 3, Range, 2 ! try all odd numbers 3, 5, 7, ... IF (Prime(Number)) THEN Count = Count + 1 ! yes, this Number is a prime WRITE(*,*) 'Prime number #', Count, ': ', Number END IF END DO WRITE(*,*) WRITE(*,*) CONTAINS ! ! ! ! ! ! -------------------------------------------------------------------INTEGER FUNCTION GetNumber() This function does not require any formal argument. It keeps asking the reader for an integer until the input value is greater than or equal to 2. -------------------------------------------------------------------INTEGER FUNCTION GetNumber()
'There are ', Count, ' primes in the range of 2 and ', Range
IMPLICIT
NONE
INTEGER :: Input WRITE(*,*) 'What is the range ? ' DO ! keep trying to read a good input READ(*,*) Input ! ask for an input integer IF (Input >= 2) EXIT ! if it is GOOD, exit WRITE(*,*) 'The range value must be >= 2. Your input = ', Input WRITE(*,*) 'Please try again:' ! otherwise, bug the user END DO GetNumber = Input END FUNCTION GetNumber ! ! ! ! ! ! -------------------------------------------------------------------LOGICAL FUNCTION Prime() This function receives an INTEGER formal argument Number. If it is a prime number, .TRUE. is returned; otherwise, this function returns .FALSE. -------------------------------------------------------------------LOGICAL FUNCTION Prime(Number) IMPLICIT NONE INTEGER, INTENT(IN) :: Number INTEGER :: Divisor IF (Number < 2) THEN Prime = .FALSE. ELSE IF (Number == 2) THEN Prime = .TRUE. ELSE IF (MOD(Number,2) == 0) THEN Prime = .FALSE. ELSE Divisor = 3 DO IF (Divisor*Divisor>Number .OR. MOD(Number,Divisor)==0) Divisor = Divisor + 2 END DO Prime = Divisor*Divisor > Number END IF END FUNCTION Prime END PROGRAM Primes
EXIT
What is the range ? -10 The range value must be >= 2. Please try again: 0 The range value must be >= 2. Please try again: 60 Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime Prime number number number number number number number number number number number number number number number number number #1: 2 #2: 3 #3: 5 #4: 7 #5: 11 #6: 13 #7: 17 #8: 19 #9: 23 #10: 29 #11: 31 #12: 37 #13: 41 #14: 43 #15: 47 #16: 53 #17: 59
Your input = 0
Discussion
q
Function GetNumber() has no formal arguments. It keeps asking the user to input an integer that is greater than or equal to two. The valid input is returned as the function value. The core part of this program is LOGICAL function Prime(). It receives an INTEGER formal argument Number and returns .TRUE. if Number is a prime number. For the working detail and logic of this function, please click here to bring you to the example discussed previously.
This function has a root near -0.89. Since this process keeps dividing the intervals into two equal halves, it is usually referred to as the bisection method. It is also known as Bozano's method.
Solution
! -------------------------------------------------------------------! This program solves equations with the Bisection Method. Given ! a function f(x) = 0. The bisection method starts with two values, ! a and b such that f(a) and f(b) have opposite signs. That is,
! ! ! ! ! !
f(a)*f(b) < 0. Then, it is guaranteed that f(x)=0 has a root in the range of a and b. This program reads in a and b (Left and Right in this program) and find the root in [a,b]. In the following, function f() is REAL FUNCTION Funct() and solve() is the function for solving the equation. --------------------------------------------------------------------
PROGRAM Bisection IMPLICIT NONE REAL, PARAMETER :: Tolerance = 0.00001 REAL :: Left, fLeft REAL :: Right, fRight REAL :: Root WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) WRITE(*,*) READ(*,*) 'This program can solves equation F(x) = 0' 'Please enter two values Left and Right such that ' 'F(Left) and F(Right) have opposite signs.' 'Left and Right please --> ' Left, Right ! read in Left and Right
fLeft = Funct(Left) ! compute their function values fRight = Funct(Right) WRITE(*,*) WRITE(*,*) 'Left = ', Left, ' f(Left) = ', fLeft WRITE(*,*) 'Right = ', Right, ' f(Right) = ', fRight WRITE(*,*) IF (fLeft*fRight > 0.0) THEN WRITE(*,*) '*** ERROR: f(Left)*f(Right) must be negative ***' ELSE Root = Solve(Left, Right, Tolerance) WRITE(*,*) 'A root is ', Root END IF CONTAINS ! ! ! ! ! ! ! -------------------------------------------------------------------REAL FUNCTION Funct() This is for function f(x). It takes a REAL formal argument and returns the value of f() at x. The following is sample function with a root in the range of -10.0 and 0.0. You can change the expression with your own function. -------------------------------------------------------------------REAL FUNCTION Funct(x) IMPLICIT NONE REAL, INTENT(IN) :: x REAL, PARAMETER :: PI = 3.1415926 REAL, PARAMETER :: a = 0.8475
-------------------------------------------------------------------REAL FUNCTION Solve() This function takes Left - the left end, Right - the right end, and Tolerance - a tolerance value such that f(Left)*f(Right) < 0 and find a root in the range of Left and Right. This function works as follows. Because of INTENT(IN), this function cannot change the values of Left and Right and therefore the values of Left and Right are saved to a and b. Then, the middle point c=(a+b)/2 and its function value f(c) is computed. If f(a)*f(c) < 0, then a root is in [a,c]; otherwise, a root is in [c,b]. In the former case, replacing b and f(b) with c and f(c), we still maintain that a root in [a,b]. In the latter, replacing a and f(a) with c and f(c) will keep a root in [a,b]. This process will continue until |f(c)| is less than Tolerance and hence c can be considered as a root. -------------------------------------------------------------------REAL FUNCTION Solve(Left, Right, Tolerance) IMPLICIT NONE REAL, INTENT(IN) :: Left, Right, Tolerance REAL :: a, Fa, b, Fb, c, Fc a = Left b = Right ! save Left and Right
Fa = Funct(a) ! Fb = Funct(b) IF (ABS(Fa) < Tolerance) THEN ! Solve = a ! ELSE IF (ABS(Fb) < Tolerance) THEN Solve = b ! ELSE ! DO ! c = (a + b)/2.0 ! Fc = Funct(c) ! IF (ABS(Fc) < Tolerance) THEN Solve = c ! EXIT ELSE IF (Fa*Fc < 0.0) THEN ! b = c ! Fb = Fc ! ELSE ! a = c ! Fa = Fc ! END IF END DO ! END IF
compute the function values if f(a) is already small then a is a root ! is f(b) is small then b is a root otherwise, iterate .... compute the middle point and its function value ! is it very small? yes, c is a root do f(a)*f(c) < 0 ? replace b with c and f(b) with f(c) then f(c)*f(b) < 0 holds replace a with c and f(a) with f(c) go back and do it again
Solve
Bisection
A root is -0.89050293 The following output shows that the function values of the input do not have opposite signs and hence program stops. This program solves equation F(x) = 0 Please enter two values Left and Right such that F(Left) and F(Right) have opposite signs. Left and Right please --> -10.0 -1.0 Left = -10. Right = -1. f(Left) = -9.902540594E-2 f(Right) = -4.495930672E-2
Discussion
q q
q q q
Function Funct(x) returns the function value at x. The heart of this program is function Solve(). It takes three arguments Left, Right and Tolerance and finds a root in the range of Left and Right. Since arguments Left and Right are declared with INTENT(IN), their values cannot be changed. As a result, their values are copied to variables a and b. The function values of a and b are stored in Fa and Fb. If the absolute value of Fa (resp., Fb) is very small, one can consider a (resp., b) as a root of the given equation. Otherwise, the midpoint c of a and b and its function value Fc are computed. If Fc is very small, c is considered as a root.
Then if Fa and Fc have opposite signs, replacing b and Fb with c and Fc, respectively. If Fa and Fc have the same sign, then Fc and Fb must have the opposite sign. In this case, a and Fa are replaced with c and Fc. Either way, the original interval [a,b] is replaced with a new one with half length. This process continues until the absolute value of the function value at c, Fc, is smaller than the given tolerance value. In this case, c is considered a root of the given equation.
What is a Module?
What is a Module?
In many previous example, there are several internal functions packed at the end of the main program. In fact, many of them such as Factorial(), Combinatorial(), GCD(), and Prime() are general functions that can also be used in other programs. To provide the programmers with a way of packing commonly used functions into a few tool-boxes, Fortran 90 has a new capability called modules. It has a syntactic form very similar to a main program, except for something that are specific to modules.
Syntax
The following is the syntax of a module: MODULE module-name IMPLICIT NONE [specification part] CONTAINS [internal-functions] END MODULE module-name The differences between a program and a module are the following:
q q
The structure of a module is almost identical to the structure of a program. However, a module starts with the keyword MODULE and ends with END MODULE rather than PROGRAM and END PROGRAM. A module has specification part and could contain internal function; but, it does not have any statements between the specification part and the keyword CONTAINS. Consequently, a module does not contains statements to be executed as in a program. A module can only contain declarations and functions to be used by other modules and programs. This is perhaps one of the most important difference. As a result, a module cannot exist alone; it must be used with other modules and a main program
Short Examples
Here are some short examples of modules:
q
The following is a very simple module. It has the specification part and does not have any internal function. The specification part has two REAL PARAMETERs, namely PI and g and one INTEGER variable Counter. MODULE SomeConstants IMPLICIT NONE REAL, PARAMETER :: PI = 3.1415926 REAL, PARAMETER :: g = 980 INTEGER :: Counter END MODULE SomeConstants
What is a Module?
The following module SumAverage does not have any specification part (hence no IMPLICIT NONE); but it does contain two functions, Sum() and Average(). Please note that function Average() uses Sum() to compute the sum of three REAL numbers. MODULE SumAverage
CONTAINS REAL FUNCTION Sum(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c Sum = a + b + c END FUNCTION Sum REAL FUNCTION Average(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c Average = Sum(a,b,c)/2.0 END FUNCTION Average END MODULE
q
SumAverage
The following module DegreeRadianConversion contains two PARAMETERs, PI and Degree180, and two functions DegreeToRadian() and RadianToDegree(). The two PARAMETERs are used in the conversion functions. Note that these parameters are global to the two functions. See scope rules for the details. MODULE DegreeRadianConversion IMPLICIT NONE REAL, PARAMETER :: PI = 3.1415926 REAL, PARAMETER :: Degree180 = 180.0 REAL FUNCTION DegreeToRadian(Degree) IMPLICIT NONE REAL, INTENT(IN) :: Degree DegreeToRadian = Degree*PI/Degree180 END FUNCTION DegreeToRadian REAL FUNCTION RadianToDegree(radian) IMPLICIT NONE REAL, INTENT(IN) :: Radian RadianToDegree = Radian*Degree180/PI END FUNCTION RadianToDegree END MODULE DegreeRadianConversion
Syntax
The following form is the syntax of a module: USE USE module-name module-name, ONLY: name-1, name-2, ..., name-n
The first indicates that the current program or module wants to use the module whose name is module-name. For example, the following main program indicates that it wants to use the content of module SomeConstants: PROGRAM MainProgram USE SomeConstants IMPLICIT NONE .......... END PROGRAM MainProgram Once a USEis specified in a program or in a module, every global entities of that used module (i.e., PARAMETERs, variables, and internal functions) becomes available to this program or this module. For example, if module SomeConstantsis: MODULE SomeConstants IMPLICIT NONE REAL, PARAMETER :: PI = 3.1415926 REAL, PARAMETER :: g = 980 INTEGER :: Counter END MODULE SomeConstants Then, program MainProgramcan access to PARAMETERs PIand gand variable Counter. However, under many circumstances, a program or a module does not want to use everything of the used module. For example, if program MainProgram only wants to use PARAMETER PI and variable Counter and does not want to use g, then the second form becomes very useful. In this case, one should add the keyword ONLY followed by a colon :, followed by a list of names that the current program or module wants to use. PROGRAM MainProgram USE SomeConstants, ONLY: PI, Counter IMPLICIT NONE ..........
END PROGRAM
MainProgram
Thus, MainProgramcan use PIand Counterof module SomeConstants; but, MainProgramcannot use g! USE with ONLY: is very handy, because it could only "import" those important and vital information and "ignore" those un-wanted ones.
q
There is a third, not recommended form, that can help to rename the names of a module locally. If a module has a name abc, in a program with a USE, one can use a new name for abc. The way of writing this renaming is the following: new-name => name-in-module For example, if one wants to give a new name to Counterof module SomeConstants, one should write: NewCounter => Counter Thus, in a program, whenever it uses MyCounter, this program is actually using Counterof module SomeConstants. This kind of renaming can be used with ONLY: or without ONLY:. PROGRAM MainProgram USE SomeConstants, ONLY: PI, MyCounter => Counter IMPLICIT NONE .......... END PROGRAM MainProgram The above example wants to use PIof module SomeConstants. In this case, when program MainProgramuses PI, it actually uses the PIof module SomeConstants. Program MainProgramalso uses Counterof module SomeConstants; but, in this case, since there is a renaming, when MainProgramuses MyCounterit actually uses Counterof module SomeConstants. Renaming does not require ONLY:. In the following, MainProgram can use all contents of module SomeConstants. When MainProgram uses PI and g, it uses the PI and g of module SomeConstants; however, when MainProgram uses MyCounter, it actually uses Counter of module SomeConstants. PROGRAM MainProgram USE SomeConstants, MyCounter => Counter IMPLICIT NONE .......... END PROGRAM MainProgram Why do we need renaming? It is simple. In your program, you may have a variable whose name is identical to an entity of a module that is being USEed. In this case, renaming the variable name would clear the ambiguity. PROGRAM MainProgram USE SomeConstants, GravityConstant => g IMPLICIT NONE
INTEGER :: e, f, g .......... END PROGRAM MainProgram In the above example, since MainProgramhas a variable called g, which is the same as PARAMETERgin module SomeConstants. By renaming gof SomeConstants, MainProgramcan use variable gfor the variable and GravityConstantfor the PARAMETERgin module SomeConstants. However, renaming is not a recommended feature. You should avoid using it whenever possible.
Then, you will have a file main.o. Now you have four .o files main.o, compute.o, convert.o and constants.o. To pull them into an executable, you need f90 compute.o convert.o constants.o main.o This would generate a.out. Or, you may want to use f90 compute.o convert.o constants.o main.o -o main so that your executable could be called main. If you want compile your main program main.f90 with all .o files, then you need f90 compute.o convert.o constants.o main.c or f90 compute.o convert.o constants.o main.c -o main Note that the order of listing these .o files may be important. Please consult the rules discussed earlier.
where 0 <= r <= n must hold. Write a module that contains two functions: (1) Factorial() and (2) Combinatorial(). The former computes the factorial of its argument, while the latter uses the former to compute the combinatorial coefficient. Then, write a main program that uses this module.
Solution
The following is the desired module: ! ! ! ! ! ! ! -------------------------------------------------------------------MODULE FactorialModule This module contains two procedures: Factorial(n) and Combinatorial(n,r). The first computes the factorial of an integer n and the second computes the combinatorial coefficient of two integers n and r. --------------------------------------------------------------------
MODULE FactorialModule IMPLICIT NONE CONTAINS ! ! ! ! ! -------------------------------------------------------------------FUNCTION Factorial() : This function accepts a non-negative integers and returns its Factorial. -------------------------------------------------------------------INTEGER FUNCTION Factorial(n) IMPLICIT NONE INTEGER, INTENT(IN) :: n INTEGER :: Fact, i Fact = 1 DO i = 1, n ! the argument ! result ! initially, n!=1 ! this loop multiplies
! i to n!
-------------------------------------------------------------------FUNCTION Combinarotial(): This function computes the combinatorial coefficient C(n,r). If 0 <= r <= n, this function returns C(n,r), which is computed as C(n,r) = n!/(r!*(n-r)!). Otherwise, it returns 0, indicating an error has occurred. -------------------------------------------------------------------INTEGER FUNCTION Combinatorial(n, r) IMPLICIT NONE INTEGER, INTENT(IN) :: n, r INTEGER :: Cnr IF (0 <= r .AND. r <= n) THEN ! valid arguments ? Cnr = Factorial(n) / (Factorial(r)*Factorial(n-r)) ELSE ! no, Cnr = 0 ! zero is returned END IF Combinatorial = Cnr END FUNCTION Combinatorial
END MODULE
FactorialModule
Click here to download this program. Here is the main program: ! ! ! ! ! -------------------------------------------------------------------PROGRAM ComputeFactorial: This program uses MODULE FactorialModule for computing factorial and combinatorial coefficients. -------------------------------------------------------------------ComputeFactorial FactorialModule NONE
PROGRAM USE
! use a module
IMPLICIT
WRITE(*,*) WRITE(*,*)
N, R,
IF (R <= N) THEN ! if r <= n, do C(n,r) WRITE(*,*) 'C(', N, ',', R, ') = ', Combinatorial(N, R) ELSE ! otherwise, do C(r,n) WRITE(*,*) 'C(', R, ',', N, ') = ', Combinatorial(R, N) END IF END PROGRAM ComputeFactorial
Discussion
q
q q
The computation of combinatorial coefficients has been discussed in an programming example, where functions Cnr (n,r) and Factorial(k) are internal functions of the main program. In this version, functions Factorial(n) and Combinatorial(n,r) are moved to a module called FactorialModule as internal functions of that module. Factorial(n) takes a non-negative integer and returns its factorial. Combinatorial(n,r) takes two non-negative integers n and r. If 0 <= r <= n, the combinatorial coefficient C(n,r) is returned; otherwise, 0 is returned. Note that in module FactorialModule, there is no variables global to its internal functions. All internal functions use their own internal (or local) variables. This module does not perform many checks as in a previous programming example. But, it is not difficult to add these tests. After moving the computation functions to a module, the main program becomes simpler. In the beginning, the main program must USES FactorialModule so that functions Factorial() and Combinatorial() can be accessed from within the main program. The main program reads in values for n and r. If r <= n, the combinatorial coefficient C(n,r) is computed by calling Combinatorial(n,r); otherwise, the main program computes Combinatorial(r,n). If the main program and module FactorialModule are stored in files fact-1p.f90 and fact-m.f90, respectively, then you can compile them together with the following command: f90 fact-m.f90 fact-1p.90
or with the following that generates an executable called fact1p: f90 fact-m.f90 fact-1p.90 -o fact-1p
Solution
The following is the desired module: ! -------------------------------------------------------------------! MODULE MyTrigonometricFunctions: ! This module provides the following functions and constants ! (1) RadianToDegree() - converts its argument in radian to ! degree ! (2) DegreeToRadian() - converts its argument in degree to ! radian ! (3) MySIN() - compute the sine of its argument in ! degree ! (4) MyCOS() - compute the cosine of its argument ! in degree ! -------------------------------------------------------------------MODULE MyTrigonometricFunctions IMPLICIT NONE REAL, REAL, REAL, REAL, CONTAINS ! ! ! ! ! -------------------------------------------------------------------FUNCTION RadianToDegree(): This function takes a REAL argument in radian and converts it to the equivalent degree. -------------------------------------------------------------------REAL FUNCTION RadianToDegree(Radian) IMPLICIT NONE REAL, INTENT(IN) :: Radian PARAMETER PARAMETER PARAMETER PARAMETER :: :: :: :: PI Degree180 R_to_D D_to_R = = = = 3.1415926 180.0 Degree180/PI PI/Degree180 ! some constants
RadianToDegree = Radian * R_to_D END FUNCTION RadianToDegree ! ! ! ! ! -------------------------------------------------------------------FUNCTION DegreeToRadian(): This function takes a REAL argument in degree and converts it to the equivalent radian. -------------------------------------------------------------------REAL FUNCTION DegreeToRadian(Degree) IMPLICIT NONE REAL, INTENT(IN) :: Degree DegreeToRadian = Degree * D_to_R END FUNCTION DegreeToRadian ! ! ! ! ! ! -------------------------------------------------------------------FUNCTION MySIN(): This function takes a REAL argument in degree and computes its sine value. It does the computation by converting its argument to radian and uses Fortran's sin(). -------------------------------------------------------------------REAL FUNCTION MySIN(x) IMPLICIT NONE REAL, INTENT(IN) :: x MySIN = SIN(DegreeToRadian(x)) END FUNCTION MySIN ! ! ! ! ! ! -------------------------------------------------------------------FUNCTION MySIN(): This function takes a REAL argument in degree and computes its cosine value. It does the computation by converting its argument to radian and uses Fortran's cos(). -------------------------------------------------------------------REAL FUNCTION MyCOS(x) IMPLICIT NONE REAL, INTENT(IN) :: x MyCOS = COS(DegreeToRadian(x)) END FUNCTION MyCOS END MODULE MyTrigonometricFunctions
Click here to download this program. Here is the main program: ! ----------------------------------------------------------------------http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/trigon.html (2 of 5)8/5/2006 8:10:55 PM
! ! ! ! ! ! ! !
PROGRAM TrigonFunctTest: This program tests the functions in module MyTrigonometricFunctions. Module MyTrigonometricFunctions is stored in file trigon.f90. Functions in that module use degree rather than radian. This program displays the sin(x) and cos(x) values for x=-180, -170, ..., 0, 10, 20, 30, ..., 160, 170 and 180. Note that the sin() and cos() function in module MyTrigonometricFunctions are named MySIN(x) and MyCOS(x). -----------------------------------------------------------------------
PROGRAM TrigonFunctTest USE MyTrigonometricFunctions IMPLICIT REAL REAL REAL REAL :: :: :: :: NONE Begin = -180.0 Final = 180.0 Step = 10.0 x
! use a module
WRITE(*,*) 'Value of PI = ', PI WRITE(*,*) x = Begin ! start with 180 degree DO IF (x > Final) EXIT ! if x > 180 degree, EXIT WRITE(*,*) 'x = ', x, 'deg sin(x) = ', MySIN(x), & ' cos(x) = ', MyCOS(x) x = x + Step ! advance x END DO END PROGRAM TrigonFunctTest
x x x x x x x x x x x x x x x x x x x x x x x x x x x
= = = = = = = = = = = = = = = = = = = = = = = = = = =
-80.deg -70.deg -60.deg -50.deg -40.deg -30.deg -20.deg -10.deg 0.E+0deg 10.deg 20.deg 30.deg 40.deg 50.deg 60.deg 70.deg 80.deg 90.deg 100.deg 110.deg 120.deg 130.deg 140.deg 150.deg 160.deg 170.deg 180.deg
sin(x) = -0.98480773 cos(x) = 0.173648223 sin(x) = -0.939692616 cos(x) = 0.342020154 sin(x) = -0.866025448 cos(x) = 0.49999997 sin(x) = -0.766044438 cos(x) = 0.642787635 sin(x) = -0.642787576 cos(x) = 0.766044438 sin(x) = -0.5 cos(x) = 0.866025388 sin(x) = -0.342020124 cos(x) = 0.939692616 sin(x) = -0.173648179 cos(x) = 0.98480773 sin(x) = 0.E+0 cos(x) = 1. sin(x) = 0.173648179 cos(x) = 0.98480773 sin(x) = 0.342020124 cos(x) = 0.939692616 sin(x) = 0.5 cos(x) = 0.866025388 sin(x) = 0.642787576 cos(x) = 0.766044438 sin(x) = 0.766044438 cos(x) = 0.642787635 sin(x) = 0.866025448 cos(x) = 0.49999997 sin(x) = 0.939692616 cos(x) = 0.342020154 sin(x) = 0.98480773 cos(x) = 0.173648223 sin(x) = 1. cos(x) = -4.371138829E-8 sin(x) = 0.98480773 cos(x) = -0.173648193 sin(x) = 0.939692616 cos(x) = -0.342020124 sin(x) = 0.866025388 cos(x) = -0.50000006 sin(x) = 0.766044438 cos(x) = -0.642787635 sin(x) = 0.642787635 cos(x) = -0.766044438 sin(x) = 0.50000006 cos(x) = -0.866025388 sin(x) = 0.342020214 cos(x) = -0.939692616 sin(x) = 0.173648298 cos(x) = -0.98480773 sin(x) = -8.742277657E-8 cos(x) = -1.
Discussion
q
q q
Module MyTrigonometricFunctions defines four constants: 1. PI, 2. Degree180, 3. R_to_D for radian to degree conversion, and 4. D_to_R for degree to radian conversion. Module MyTrigonometricFunctions contains four functions: 1. RadianToDegree() converts its radian argument to degree; 2. DegreeToRadian() converts its degree argument to radian; 3. MySIN() takes a degree argument and returns its sine value; and 4. MyCOS() takes a degree argument and returns its cosine value. In the module, MySIN(x) first converts its degree argument x to radian using function DegreeToRadian() and supplies the result to the Fortran SIN() function for computing the value of sine. The module uses MySIN() and MyCOS() rather than the same Fortran names SIN() and COS() to avoid confusion. As described in the use of modules, the main program can use variables, PARAMETERs and functions declared and defined in a module. Thus, the main program can use the value of PARAMETER PI defined in module MyTrigonometricFunctions. This is why there is no declaration of PI in the main program. In the main program, REAL variable x starts with 180 (in degree) and steps through 180 (in degree) with a step size 10. For each value of x, its SIN() and COS() is computed. If the main program and module MyTrigonometricFunctions are stored in files trigon.f90 and tri-test.f90,
respectively, then you can compile them together with the following command: f90 trigon.f90 tri-test.90 or with the following that generates an executable called tri-test: f90 trigon.f90 tri-test.90 -o tri-test
Syntax
The following is the syntax of a module: PUBLIC :: name-1, name-2, ..., name-n
PRIVATE :: name-1, name-2, ..., name-n All entities listed in PRIVATE will not be accessible from outside of the module and all entities listed in PUBLIC can be accessed from outside of the module. All not listed entities, by default, can be accessed from outside of the module. You can have many PRIVATE and PUBLIC statements. In the following code segment, since VolumeOfDeathStar, SecretConstant and BlackKnight are listed in a statement, they can only be used with the module. On the other hand, SkyWalker and Princess are listed in PUBLIC, they can be accessed from outside of the module. There are entities not listed: function WeaponPower() and DeathStar. By default, they are public and can be accessed from outside of the module. MODULE TheForce IMPLICIT NONE INTEGER :: SkyWalker, Princess REAL :: BlackKnight LOGICAL :: DeathStar REAL, PARAMETER :: SecretConstant = 0.123456 PUBLIC :: SkyWalker, Princess PRIVATE :: VolumeOfDeathStar PRIVATE :: SecretConstant, BlackKnight CONTAINS INTEGER FUNCTION VolumeOfDeathStar() .......... END FUNCTION WolumeOfDeathStar REAL FUNCTION .......... END FUNCTION WeaponPower(SomeWeapon)
A Programming Example
In a previous example of using degree in trigonometric functions, four constants and four functions are defined. But, most of them are used in and meaningful to the module MyTrigonometricFunctions. Thus, one can make them private so that they cannot be accessed from outside of this module. Here is a rewritten version: ! -------------------------------------------------------------------! MODULE MyTrigonometricFunctions: ! This module provides the following functions and constants ! (1) RadianToDegree() - converts its argument in radian to ! degree ! (2) DegreeToRadian() - converts its argument in degree to ! radian ! (3) MySIN() - compute the sine of its argument in ! degree ! (4) MyCOS() - compute the cosine of its argument ! in degree ! -------------------------------------------------------------------MODULE MyTrigonometricFunctions IMPLICIT NONE REAL, REAL, REAL, REAL, PARAMETER PARAMETER PARAMETER PARAMETER :: :: :: :: PI Degree180 R_to_D D_to_R = = = = 3.1415926 180.0 Degree180/PI PI/Degree180 ! some constants
-------------------------------------------------------------------FUNCTION RadianToDegree(): This function takes a REAL argument in radian and converts it to the equivalent degree. -------------------------------------------------------------------REAL FUNCTION RadianToDegree(Radian) IMPLICIT NONE REAL, INTENT(IN) :: Radian RadianToDegree = Radian * R_to_D
END FUNCTION ! ! ! ! !
RadianToDegree
-------------------------------------------------------------------FUNCTION DegreeToRadian(): This function takes a REAL argument in degree and converts it to the equivalent radian. -------------------------------------------------------------------REAL FUNCTION DegreeToRadian(Degree) IMPLICIT NONE REAL, INTENT(IN) :: Degree DegreeToRadian = Degree * D_to_R END FUNCTION DegreeToRadian
! ! ! ! ! !
-------------------------------------------------------------------FUNCTION MySIN(): This function takes a REAL argument in degree and computes its sine value. It does the computation by converting its argument to radian and uses Fortran's sin(). -------------------------------------------------------------------REAL FUNCTION MySIN(x) IMPLICIT NONE REAL, INTENT(IN) :: x MySIN = SIN(DegreeToRadian(x)) END FUNCTION MySIN
! ! ! ! ! !
-------------------------------------------------------------------FUNCTION MySIN(): This function takes a REAL argument in degree and computes its cosine value. It does the computation by converting its argument to radian and uses Fortran's cos(). -------------------------------------------------------------------REAL FUNCTION MyCOS(x) IMPLICIT NONE REAL, INTENT(IN) :: x MyCOS = COS(DegreeToRadian(x)) END FUNCTION MyCOS
END MODULE
MyTrigonometricFunctions
Click here to download this module. You also need a main program to test it. This mean program is identical to the one used in a previous example. If you need it, click here to download a copy. In this module, there are four PARAMETERs. Of these four, only PI is not listed as PRIVATE and hence can be accessed from outside of this module. There are four internal functions, MySIN(), MyCOS(), RadianToDegree() and DegreeToRadian(). The former two are listed as PUBLIC and can be accessed from outside of this module. The latter two
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/mod-private.html (3 of 4)8/5/2006 8:10:57 PM
are listed as PRIVATE and therefore cannot be accessed from outside of this module. Note that if PI is also made PRIVATE, then the main program will have a mistake since it displays the value of PI: PROGRAM TrigonFunctTest USE MyTrigonometricFunctions IMPLICIT NONE .......... WRITE(*,*) 'Value of PI = ', PI .......... END PROGRAM TrigonFunctTest
Interface Blocks
Interface Blocks
All functions you have seen so far are internal functions that are contained in a program or a module. Functions that are not contained in any program or modules are external functions. A program can use internal functions, external functions and functions in modules. Moreover, external functions can be in the same file of the program or in several files. External functions can be considered as program units that are independent of each other. Thus, the only way of communication among external functions, the main program and modules is through arguments. In other words, from outside of an external function, it is impossible to use its variables, PARAMETERs and internal functions. For example, your main program could be in file prog4.f90. Your functions Area() and Test() are in file area.f90 and functions ReadData() and DisplayResult() are in file InputOutput.f90. In this case, all four functions are external to the main program. To compile this three-file program, you need the following command: f90 prog4.f90 area.f90 InputOutput.f90 This will generate a a.out. Or, you can ask the Fortran compiler to generate an executable called prog4 with the following command: f90 prog4.f90 area.f90 InputOutput.f90 -o prog4 In addition to compiling these files, there is one more important thing. How does a function or a program know the way of using a function? A function has a name, some arguments with certain types, and the type of the function value? Without these information, a function might not be used correctly. To overcome this problem, an interface block is introduced. More precisely, any external function to be used should be listed in an interface block along with the declaration of its arguments and their types and the type of the function value. Note that an external function can be in the file containing the main program or module. As long as that function is not contained in any program, function, or module, it is external and an interface block is required in any program, function or module where this function is used.
Syntax
The syntax of an interface block is the following: INTERFACE type FUNCTION name(arg-1, arg-2, ..., arg-n) type, INTENT(IN) :: arg-1 type, INTENT(IN) :: arg-2 .......... type, INTENT(IN) :: arg-n END FUNCTION name ....... other functions ....... END INTERFACE
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/interface.html (1 of 3)8/5/2006 8:10:58 PM
Interface Blocks
An interface block starts with the keyword INTERFACE and ends with END INTERFACE. For each external function to be used in a program, module or a function, it should have an entry in an interface block. The information that should be included are 1. the function header that contains the types of the function value, function name, and arguments, 2. the declaration of each argument, and 3. the END FUNCTION statement. Note that only the types of argument and their INTENT are important. You can use other names for the arguments; but, it would be a bad practice. In fact, you can copy these information from that function's declarations to an interface block. For example, if there are two external functions in a file as follows: INTEGER FUNCTION Coin(value) IMPLICIT NONE INTEGER, INTENT(IN) :: value ........... END FUNCTION Coin REAL FUNCTION Volume(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c ........... END FUNCTION Volume The corresponding interface block (if both functions are used) is INTERFACE INTEGER FUNCTION Coin(value) INTEGER, INTENT(IN) :: value END FUNCTION Coin REAL FUNCTION Volume(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION Volume END INTERFACE If only function Volume() is used, one can just copy the information of Volume() to interface block as follows: INTERFACE REAL FUNCTION Volume(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION Volume END INTERFACE
Interface Blocks
The answer is simple. Put it after the IMPLICIT NONE statement. Thus, if the main program needs to use external functions Coin() and Volume(), the following shows the place for the interface block: PROGRAM CoinVolume IMPLICIT NONE INTERFACE INTEGER FUNCTION Coin(value) INTEGER, INTENT(IN) :: value END FUNCTION Coin REAL FUNCTION Volume(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION Volume END INTERFACE ..... other specification statements ..... ......... executable statements .......... END PROGRAM CoinVolume
Solution
The following solution has the main program and the two conversion functions in the same file. The order of placing these functions and the main program in the file is unimportant. ! ! ! ! ! ! ! ! ! ! --------------------------------------------------------------This program "contains" two REAL functions: (1) Cm_to_Inch() takes a real inch unit and converts it to cm unit, and (2) Inch_to_cm() takes a real cm unit and converts it to inch unit. The main program uses these functions to convert 0, 0.5, 1, 1.5, 2.0, 2.5, ..., 8.0, 8.5, 9.0, 9.5 and 10.0 inch (resp., cm) to cm (resp., inch). ---------------------------------------------------------------
PROGRAM Conversion IMPLICIT NONE INTERFACE REAL FUNCTION Cm_to_Inch(cm) REAL, INTENT(IN) :: cm END FUNCTION Cm_to_Inch REAL FUNCTION Inch_to_Cm(inch) REAL, INTENT(IN) :: inch END FUNCTION Inch_to_Cm END INTERFACE REAL, PARAMETER :: Initial = 0.0, Final = 10.0, Step = 0.5 REAL :: x x = Initial DO ! x = 0, 0.5, 1.0, ..., 9.0, 9.5, 10 IF (x > Final) EXIT WRITE(*,*) x, 'cm = ', Cm_to_Inch(x), 'inch and ', & x, 'inch = ', Inch_to_Cm(x), 'cm'
! --------------------------------------------------------------! REAL FUNCTION Cm_to_Inch() ! This function converts its real input in cm to inch. ! --------------------------------------------------------------REAL FUNCTION Cm_to_Inch(cm) IMPLICIT NONE REAL, INTENT(IN) :: cm REAL, PARAMETER :: To_Inch = 0.3937 Cm_to_Inch = To_Inch * cm END FUNCTION Cm_to_Inch ! --------------------------------------------------------------! REAL FUNCTION Inch_to_Cm() ! This function converts its real input in inch to cm. ! --------------------------------------------------------------REAL FUNCTION Inch_to_Cm(inch) IMPLICIT NONE REAL, INTENT(IN) :: inch REAL, PARAMETER :: To_Cm = 2.54 Inch_to_Cm = To_Cm * inch END FUNCTION Inch_to_Cm Click here to download this program.
! conversion factor
! conversion factor
5.cm = 1.96850002inch and 5.inch = 5.5cm = 2.16534996inch and 5.5inch 6.cm = 2.36220002inch and 6.inch = 6.5cm = 2.55905008inch and 6.5inch 7.cm = 2.75589991inch and 7.inch = 7.5cm = 2.95274997inch and 7.5inch 8.cm = 3.14960003inch and 8.inch = 8.5cm = 3.34645009inch and 8.5inch 9.cm = 3.54330015inch and 9.inch = 9.5cm = 3.74014997inch and 9.5inch 10.cm = 3.93700004inch and 10.inch
12.6999998cm = 13.9699993cm 15.2399998cm = 16.5100002cm 17.7799988cm = 19.0499992cm 20.3199997cm = 21.5900002cm 22.8600006cm = 24.1299992cm = 25.3999996cm
Discussion
q
External function Cm_to_Inch() converts its formal argument cm to inch, which is returned as the function value. Please note that the constant 0.3937 is defined to be a PARAMETER. External function Inch_to_Cm() converts its formal argument inch to cm, which is returned as the function value. Please note that the constant 2.54 is defined to be a PARAMETER. The main program uses DO-EXIT-END DO to generate 0, 0.5, 1, 1.5, ..., 8, 8.5, 9, 9.5 and 10. For each value, Cm_to_Inch() and Inch_to_Cm() are called to perform conversion. To provide the main program with correct information of the two external functions, the following interface block is inserted in the beginning of the main program: INTERFACE REAL FUNCTION Cm_to_Inch(cm) REAL, INTENT(IN) :: cm END FUNCTION Cm_to_Inch REAL FUNCTION Inch_to_Cm(inch) REAL, INTENT(IN) :: inch END FUNCTION Inch_to_Cm END INTERFACE
In order for a, b and c to form a triangle, two conditions must be satisfied. First, all side lengths must be positive:
Second, the sum of any two side lengths must be greater than the third side length:
Write a program to read in three real values and use a function for testing the conditions and another function for computing the area. Should the conditions fail, your program must keep asking the user to re-enter the input until the input form a triangle. Then, the other function is used to compute the area.
Solution
! -------------------------------------------------------------------! This program uses Heron's formula to compute the area of a ! triangle. It "contains" the following functions; ! (1) LOGICAL function TriangleTest() ! this function has three real formal arguments and tests ! to see if they can form a triangle. If they do form a ! triangle, this function returns .TRUE.; otherwise, it ! returns .FALSE.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/area-3.html (1 of 4)8/5/2006 8:11:02 PM
! (2) REAL function TriangleArea() ! this functions has three real formal arguments considered ! as three sides of a triangle and returns the area of this ! triangle. ! -------------------------------------------------------------------PROGRAM HeronFormula IMPLICIT NONE INTERFACE LOGICAL FUNCTION TriangleTest(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION TriangleTest REAL FUNCTION Area(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION Area END INTERFACE REAL :: a, b, c, TriangleArea DO WRITE(*,*) 'Three sides of a triangle please --> ' READ(*,*) a, b, c WRITE(*,*) 'Input sides are ', a, b, c IF (TriangleTest(a, b, c)) EXIT ! exit if not a triangle WRITE(*,*) 'Your input CANNOT form a triangle. Try again' END DO TriangleArea = Area(a, b, c) WRITE(*,*) 'Triangle area is ', TriangleArea END PROGRAM ! ! ! ! ! ! ! ! ! HeronFormula
-------------------------------------------------------------------LOGICAL FUNCTION TriangleTest() : This function receives three REAL numbers and tests if they form a triangle by testing: (1) all arguments must be positive, and (2) the sum of any two is greater than the third If the arguments form a triangle, this function returns .TRUE.; otherwise, it returns .FALSE. --------------------------------------------------------------------
LOGICAL FUNCTION TriangleTest(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c LOGICAL :: test1, test2 test1 = (a > 0.0) .AND. (b > 0.0) .AND. (c > 0.0)
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap06/area-3.html (2 of 4)8/5/2006 8:11:02 PM
test2 = (a + b > c) .AND. (a + c > b) .AND. (b + c > a) TriangleTest = test1 .AND. test2 ! both must be .TRUE. END FUNCTION TriangleTest ! ! ! ! ! -------------------------------------------------------------------REAL FUNCTION Area() : This function takes three real number that form a triangle, and computes and returns the area of this triangle using Heron's formula. --------------------------------------------------------------------
REAL FUNCTION Area(a, b, c) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c REAL :: s s = (a + b + c) / 2.0 Area = SQRT(s*(s-a)*(s-b)*(s-c)) END FUNCTION Area Click here to download this program.
Discussion
q
q q
External LOGICAL function TriangleTest() receives three REAL values. The result of the first test condition is saved to a local LOGICAL variable test1, while the result of the second condition is saved to another LOGICAL variable test2. Since both conditions must be true to have a triangle, test1 and test2 are .AND.ed and the result goes into the function name so that it could be returned. External REAL function Area is simple and does not require further discussion. The main program has a DO-EXIT-END DO loop. In each iteration, it asks for three real values. These values are
sent to LOGICAL function TriangleTest() for testing. If the returned value is .TRUE., the input form a triangle and the control of execution exits. Then, the area is computed with REAL function Area(). If the returned value is . FALSE., a message is displayed and loops back asking for a new set of values. To provide the main program with all information for using the two external functions, an interface block is inserted in the beginning: INTERFACE LOGICAL FUNCTION TriangleTest(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION TriangleTest REAL FUNCTION Area(a, b, c) REAL, INTENT(IN) :: a, b, c END FUNCTION Area END INTERFACE