VIEWS: 11 PAGES: 51 POSTED ON: 11/20/2011
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 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: 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 The meaning of this counting-loop goes as follows: 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. 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 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 final-value, 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 DO Count = -3, 4, 2 WRITE(*,*) Count, Count*Count, Count*Count*Count END DO 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 initial- value 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 END DO FREQUENTLY USED LOOP TRICKS In addition to repeatedly processing some data as shown above, the DO-loop has some other uses as presented in the following examples: 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 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. SOME HELPFUL NOTES There are certain things you should know about DO-loops. 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 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 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. COUNTING POSITIVE AND NEGATIVE INPUT VALUES PROBLEM STATEMENT Given a set of integer input values, write a program to count the number of positive and negative values and compute their sums. The input is organized as follows: 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 :: Positive, Negative INTEGER :: PosSum, NegSum INTEGER :: TotalNumber, Count INTEGER :: Data Positive = 0 ! # of positive items Negative = 0 ! # of negative items PosSum = 0 ! sum of all positive items NegSum = 0 ! sum of all negative items READ(*,*) TotalNumber ! 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(*,*) ! display results WRITE(*,*) 'Counting Report:' WRITE(*,*) ' Positive items = ', Positive, ' Sum = ', PosSum WRITE(*,*) ' Negative items = ', Negative, ' Sum = ', NegSum WRITE(*,*) ' Zero items = ', TotalNumber - Positive - Negative WRITE(*,*) WRITE(*,*) 'The total of all input is ', Positive + Negative END PROGRAM Counting Click here to download this program. PROGRAM INPUT AND OUTPUT If the data shown above is stored in a file, say data.in and the above program is compiled to an executable count, then executing count < data.in will generate the following output: Input data 1: -6 Input data 2: 7 Input data 3: 2 Input data 4: -9 Input data 5: 0 Input data 6: 8 Input data 7: 0 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! COMPUTING ARITHMETIC, GEOMETRIC AND HARMONIC MEANS PROBLEM STATEMENT The arithmetic mean (i.e., average), geometric mean and harmonic mean of a set of n numbers x1, x2, ..., xn are defined as follows: 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 :: X REAL :: Sum, Product, InverseSum REAL :: Arithmetic, Geometric, Harmonic INTEGER :: Count, TotalNumber, TotalValid Sum = 0.0 ! for the sum Product = 1.0 ! for the product InverseSum = 0.0 ! for the sum of 1/x TotalValid = 0 ! # of valid items READ(*,*) 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(*,*) 'No. of valid items --> ', TotalValid WRITE(*,*) 'Arithmetic mean --> ', Arithmetic WRITE(*,*) 'Geometric mean --> ', Geometric WRITE(*,*) 'Harmonic mean --> ', Harmonic ELSE ! no, display a message WRITE(*,*) 'ERROR: none of the input is positive' END IF END PROGRAM ComputingMeans Click here to download this program. PROGRAM INPUT AND OUTPUT This program uses the same format of input as discussed in previous example. More precisely, the first line gives the number of data items, followed by that number of input line on each which is a data value. Except for the first input value, which gives the number of input, all other values are real numbers. 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 --> 5 Arithmetic mean --> 3. Geometric mean --> 2.6051712 Harmonic mean --> 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 item 1 --> 1. Input item 2 --> 2. Input item 3 --> 3. Input item 4 --> -4. Input <= 0. Ignored Input item 5 --> 5. Input item 6 --> 6. # of items read --> 6 # of valid items -> 5 Arithmetic mean --> 3.4000001 Geometric mean --> 2.82523465 Harmonic mean --> 2.27272725 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 item 1 --> -1. Input <= 0. Ignored Input item 2 --> -2. Input <= 0. Ignored Input item 3 --> 0.E+0 Input <= 0. Ignored Input item 4 --> -3. Input <= 0. Ignored ERROR: none of the input is positive DISCUSSION This example is quite simple and does not require further explanation. 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(*,*) 'This program computes the factorial of' WRITE(*,*) 'a non-negative integer' WRITE(*,*) WRITE(*,*) 'What is N in N! --> ' READ(*,*) N WRITE(*,*) 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 END DO WRITE(*,*) N, '! = ', Answer END IF END PROGRAM Factorial Click here to download this program. PROGRAM INPUT AND OUTPUT 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 13, the factorial of 15 is 13! = 1*2*3*...*13=1932053504 This program computes the factorial of a non-negative integer What is N in N! --> 13 13! = 1932053504 DISCUSSION The basics of writing a factorial computation program has been discussed in a factorial example of counting DO. It is worthwhile to note that most CPU's do not report integer overflow. As a result, on a typical computer today, the maximum factorial is around 13!. If you try this program on a PC, you should get 13! = 1932053504 and 14! = 1278945280. But, 13! > 14! is obviously incorrect. Then, we have 15! = 2004310016, 16! = 2004189184, and 17! = -288522240. These results are obviously wrong. This shows that a typical PC can only handle up to 13! GENERAL DO-LOOP WITH EXIT The general DO-loop is actually very simple. But, to use it properly, you need to be very careful, since it may never stop. The general DO-loop has a form as follows: DO statements END DO Between DO and END DO, there are statements. These statements are executed over and over without any chance to get out of the DO-loop. Here is an example, REAL :: x, y, z DO READ(*,*) x y = x*x z = x*x*x WRITE(*,*) x, ' square = ', y, ' cube = ', z END DO 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. THE EXIT STATEMENT The EXIT is as simple as writing down the word EXIT. It is used to bail out the containing loop. DO statements-1 EXIT statements-2 END DO In the above, statements-1 is executed followed by the EXIT statement. Once the EXIT statement is reached, the control leaves the inner-most DO-loop that contains the EXIT statement. Therefore, in the above case, statements- 2 will never be executed. Since it must be some reason for bailing out a DO-loop, the EXIT statement is usually used with an IF or even an IF-THEN-ELSE-END IF statement in one of the following forms. Note that these are not the only cases in which you can use EXIT. DO statements-1 IF (logical-expression) EXIT statements-2 END DO 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 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 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 SOME HELPFUL NOTES 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) EXIT WRITE(*,*) i i = i + 1 END DO 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. INTEGER :: i DO IF (i <= 3) EXIT WRITE(*,*) i i = i - 1 END DO DETERMINING THE MINIMUM AND MAXIMUM OF INPUT DATA PROBLEM STATEMENT Suppose we have a set of non-negative input integers terminated with a negative value. These input values are on separate lines. Write a program to determine the number of input data items, excluding the negative one at the end, and compute the minimum and the maximum. For example, the following input contains 7 data values with the seventh being negative. Of the six non-negative ones, the minimum and maximum are 2 and 9, respectively. 5 3 9 2 7 4 -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 COMPUTING THE SQUARE ROOT OF A POSITIVE NUMBER PROBLEM STATEMENT The square root of a positive number b can be computed with Newton's formula: 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 = 0 ! count starts with 0 X = Input ! X starts with the input value DO ! for each iteration Count = Count + 1 ! increase the iteration count NewX = 0.5*(X + Input/X) ! compute a new approximation IF (ABS(X - NewX) < Tolerance) EXIT ! if they are very close, exit X = NewX ! otherwise, keep the new one END DO WRITE(*,*) 'After ', Count, ' iterations:' WRITE(*,*) ' The estimated square root is ', NewX WRITE(*,*) ' The square root from SQRT() is ', SQRT(Input) WRITE(*,*) ' Absolute error = ', ABS(SQRT(Input) - NewX) END PROGRAM SquareRoot Click here to download this program. PROGRAM INPUT AND OUTPUT If the input are 10.0 for b and 0.00001 for the tolerance, the following output shows that it requires 6 iterations to reach an approximation of square root of 10. Comparing the result with the one obtained from Fortran intrinsic function SQRT(), the absolute error is zero. After 6 iterations: The estimated square root is 3.1622777 The square root from SQRT() is 3.1622777 Absolute error = 0.E+0 If the input are 0.5 for b and 0.00001 for the tolerance, it takes 4 iterations to reach an approximation of the square root of 0.5. The value from using Fortran intrinsic function SQRT() is 0.707106769 and again the absolute error is 0. After 4 iterations: The estimated square root is 0.707106769 The square root from SQRT() is 0.707106769 Absolute error = 0.E+0 DISCUSSION 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) 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 :: Count ! # of terms used REAL :: Term ! a term REAL :: Sum ! the sum of series REAL :: X ! the input x REAL, PARAMETER :: Tolerance = 0.00001 ! tolerance READ(*,*) X ! read in x Count = 1 ! the first term is 1 and counted Sum = 1.0 ! thus, the sum starts with 1 Term = X ! the second term is x DO ! for each term IF (ABS(Term) < Tolerance) EXIT ! if too small, exit Sum = Sum + Term ! otherwise, add to sum Count = Count + 1 ! count indicates the next term Term = Term * (X / Count) ! compute the value of next term END DO WRITE(*,*) 'After ', Count, ' iterations:' WRITE(*,*) ' Exp(', X, ') = ', Sum WRITE(*,*) ' From EXP() = ', EXP(X) WRITE(*,*) ' Abs(Error) = ', ABS(Sum - EXP(X)) END PROGRAM Exponential Click here to download this program. PROGRAM INPUT AND OUTPUT If the input value is 10.0, the following output shows that it requires 35 iterations to reach EXP(10.0)=22026.4648. Comparing the result with the one obtained from Fortran intrinsic function EXP(), the absolute error is zero. After 35 iterations: Exp(10.) = 22026.4648 From EXP() = 22026.4648 Abs(Error) = 0.E+0 If the input is -5.0, it takes 21 iterations to reach EXP(-5.0)=6.744734943E-3. The value from using Fortran intrinsic function is 6.737946998E-3 and the absolute error is 6.787944585E-6. After 21 iterations: Exp(-5.) = 6.744734943E-3 From EXP() = 6.737946998E-3 Abs(Error) = 6.787944585E-6 DISCUSSION i One obvious way of writing this program is computing each term directly using the formula x /i!. i However, this is not a wise way, since both x 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. 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). COMPUTING THE GREATEST COMMON DIVISOR OF TWO POSITIVE INTEGERS PROBLEM STATEMENT The Greatest Common Divisor, GCD for short, of two positive integers can be computed with Euclid's division algorithm. Let the given numbers be a and b, a >= b. Euclid's division algorithm has the following steps: 1. Compute the remainder c of dividing a by b. 2. If the remainder c is zero, b is the greatest common divisor. 3. If c is not zero, replace a with b and b with the remainder c. Go back to step (1). Write a program that reads in two integers and computes their greatest common divisor. Note that these two input could be in any order. 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. ! --------------------------------------------------------- PROGRAM GreatestCommonDivisor IMPLICIT NONE INTEGER :: a, b, c 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 ! now we have a <= b c = MOD(a, b) ! compute c, the reminder IF (c == 0) EXIT ! if c is zero, we are done. GCD = b a = b ! otherwise, b becomes a b = c ! and c becomes b END DO ! go back WRITE(*,*) 'The GCD is ', b END PROGRAM GreatestCommonDivisor Click here to download this program. PROGRAM INPUT AND OUTPUT 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 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 CHECKING IF A POSITIVE INTEGER IS A PRIME NUMBER PROBLEM STATEMENT An positive integer greater than or equal to 2 is a prime number if the only divisor of this integer is 1 and itself. Write a program that reads in an arbitrary integer and determines if it is a prime number. 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 :: Number ! the input number INTEGER :: Divisor ! 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) EXIT 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 END IF END PROGRAM Prime Click here to download this program. PROGRAM INPUT AND OUTPUT If the input value is -1, the output is a message saying the input is not legal. Illegal input If the input is 2, it is a prime number. 2 is a prime If the input is 3, it is also a prime number. 3 is a prime 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 97, it is a prime number. 97 is a prime If the input is 9797, it is not a prime since it is divisible by 97. 9797 is NOT a prime DISCUSSION 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 Just like an IF-THEN-ELSE-END IF can contain another IF-THEN-ELSE-END IF (see nested IF for the details), a DO-loop can contain other DO-loops in its body. The body of the contained DO-loop, usually referred to as the nested DO-loop, 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: 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(*,*) i*j END DO END DO 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. 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 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 b c 2 1 4 3 5 1 6 8 10 3 2 12 5 13 1 8 15 17 4 2 16 12 20 3 24 7 25 1 10 24 26 2 20 21 29 5 3 30 16 34 4 40 9 41 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 END DO WRITE(*,*) Sum END DO 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. COMPUTING CLASSES AVERAGES PROBLEM STATEMENT There are four sessions of CS110 and CS201, each of which has a different number of students. Suppose all students take three exams. Someone has prepared a file that records the exam scores of all students. This file has a form as follows: 4 3 97.0 87.0 90.0 100.0 78.0 89.0 65.0 70.0 76.0 2 100.0 100.0 98.0 97.0 85.0 80.0 4 78.0 75.0 90.0 89.0 85.0 90.0 100.0 97.0 98.0 56.0 76.0 65.0 3 60.0 65.0 50.0 100.0 99.0 96.0 87.0 74.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 :: NoClass ! the no. of classes INTEGER :: NoStudent ! the no. of students in each class INTEGER :: Class, Student ! DO control variables REAL :: Score1, Score2, Score3, Average REAL :: 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 Click here to download this program. PROGRAM INPUT AND OUTPUT The input shown above should produce the following output: Class 1 has 3 students 1, 97., 87., 90., 91.3333359 2, 100., 78., 89., 89. 3, 65., 70., 76., 70.3333359 ---------------------- Class Average: 87.3333359, 78.3333359, 85. 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, 75.6666641 Grant Average: 79.1111145 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(*,*) NoClass DO Class = 1, NoClass compute various average for this class display exam averages and class the grant average END DO 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 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 DO-loop 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. COMPUTING A SET OF VALUES OF EXP(X) PROBLEM STATEMENT In a previous example we have discussed the way of using infinite series for computing the exponential function EXP(x). The exponential function, EXP(x), is usually defined to be the sum of the following infinite series: 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 :: Count ! term count REAL :: Term ! a term REAL :: Sum ! the sum of series REAL :: X ! running value REAL :: ExpX ! EXP(X) REAL :: Begin, End, Step ! control values REAL, PARAMETER :: Tolerance = 0.00001 ! tolerance WRITE(*,*) 'Initial, Final and Step please --> ' READ(*,*) Begin, End, Step X = Begin ! X starts with the beginning value DO IF (X > End) EXIT ! if X is > the final value, EXIT Count = 1 ! the first term is 1 and counted Sum = 1.0 ! thus, the sum starts with 1 Term = X ! the second term is x ExpX = EXP(X) ! the exp(x) from Fortran's EXP() DO ! for each term IF (ABS(Term) < Tolerance) EXIT ! if too small, exit Sum = Sum + Term ! otherwise, add to sum Count = Count + 1 ! count indicates the next term Term = Term * (X / Count) ! compute the value of next term END DO WRITE(*,*) X, Sum, ExpX, ABS(Sum-ExpX), ABS((Sum-ExpX)/ExpX) X = X + Step END DO END PROGRAM Exponential Click here to download this program. PROGRAM INPUT AND OUTPUT If the input for Begin, End and Step are -1.0, 1.0 and 0.1, the program would generate the following output. Initial, Final and Step please --> -1., 0.367881894, 0.36787945, 2.443790436E-6, 6.642911103E-6 -0.899999976, 0.406570643, 0.40656966, 9.834766388E-7, 2.41896214E-6 -0.799999952, 0.449325144, 0.449328989, 3.844499588E-6, 8.556090506E-6 -0.699999928, 0.496584028, 0.496585339, 1.311302185E-6, 2.640638058E-6 -0.599999905, 0.5488168, 0.548811674, 5.125999451E-6, 9.340179531E-6 -0.499999911, 0.606532216, 0.606530726, 1.490116119E-6, 2.456785978E-6 -0.399999917, 0.670314729, 0.670320094, 5.36441803E-6, 8.002770301E-6 -0.299999923, 0.740817249, 0.740818262, 1.013278961E-6, 1.367783398E-6 -0.199999928, 0.818733335, 0.818730831, 2.503395081E-6, 3.05765343E-6 -9.999992698E-2, 0.904833436, 0.904837489, 4.053115845E-6, 4.479385552E- 6 7.450580597E-8, 1., 1.00000012, 1.192092896E-7, 1.192092753E-7 0.100000076, 1.10516667, 1.10517097, 4.291534424E-6, 3.883140835E-6 0.200000077, 1.22140002, 1.22140288, 2.861022949E-6, 2.342407242E-6 0.300000072, 1.34985793, 1.34985888, 9.536743164E-7, 7.064992928E-7 0.400000066, 1.4918189, 1.49182475, 5.841255188E-6, 3.915510206E-6 0.50000006, 1.64871967, 1.64872134, 1.668930054E-6, 1.012257258E-6 0.600000083, 1.82211316, 1.822119, 5.841255188E-6, 3.205748499E-6 0.700000107, 2.01375127, 2.01375294, 1.668930054E-6, 8.287660194E-7 0.800000131, 2.22553682, 2.22554111, 4.291534424E-6, 1.928310667E-6 0.900000155, 2.45960236, 2.45960355, 1.192092896E-6, 4.846687034E-7 The first column shows the data values (i.e., -1.0, -0.9, ..., 1.0), the second is the values from using infinite series with a tolerance value 0.00001, the third column contains the values from Fortran's intrinsic function EXP(), the forth column has the absolute errors, and the fifth column has the relative errors. Let S be the sum computed using infinite series and exp(x) be the result from Fortran's intrinsic function. Then, the absolute error and relative error are defined as follows: 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 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 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 ! the three digits INTEGER :: abc, a3b3c3 ! the number and its cubic sum INTEGER :: Count ! 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 Click here to download this program. PROGRAM INPUT AND OUTPUT The following is the output from the above program. Thus, there are six Armstrong numbers in the range of 0 and 999. Armstrong number 1: 0 Armstrong number 2: 1 Armstrong number 3: 153 Armstrong number 4: 370 Armstrong number 5: 371 Armstrong number 6: 407 DISCUSSION 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 FINDING ALL PRIME NUMBERS IN THE RANGE OF 2 AND N PROBLEM STATEMENT In a previous example, we have discussed how to determine if a positive integer is a prime number. In this one, we shall find all prime numbers in the range of 2 and N, where N is an input integer. Write a program to read a value of N, make sure that the value of N is greater than or equal to 2, and display all prime numbers in the range of 2 and N. In case the value of N is less than 2, your program should keep asking the user to try again until a value that is greater than or equal to 2 is read. SOLUTION ! --------------------------------------------------------------- ! This program finds all prime numbers in the range of 2 and an ! input integer. ! --------------------------------------------------------------- PROGRAM Primes IMPLICIT NONE INTEGER :: Range, Number, Divisor, Count WRITE(*,*) 'What is the range ? ' DO ! keep trying to read a good input READ(*,*) Range ! ask for an input integer IF (Range >= 2) EXIT ! if it is GOOD, exit WRITE(*,*) 'The range value must be >= 2. Your input = ', Range WRITE(*,*) 'Please try again:' ! otherwise, bug the user END DO 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 WRITE(*,*) WRITE(*,*) 'There are ', Count, ' primes in the range of 2 and ', Range END PROGRAM Primes Click here to download this program. PROGRAM INPUT AND OUTPUT 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. Your input = -10 Please try again: 0 The range value must be >= 2. Your input = 0 Please try again: 1 The range value must be >= 2. Your input = 1 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 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 number #1: 2 Prime number #2: 3 Prime number #3: 5 Prime number #4: 7 Prime number #5: 11 Prime number #6: 13 Prime number #7: 17 Prime number #8: 19 Prime number #9: 23 Prime number #10: 29 Prime number #11: 31 Prime number #12: 37 Prime number #13: 41 Prime number #14: 43 Prime number #15: 47 Prime number #16: 53 Prime number #17: 59 Prime number #18: 61 Prime number #19: 67 Prime number #20: 71 Prime number #21: 73 Prime number #22: 79 Prime number #23: 83 Prime number #24: 89 Prime number #25: 97 There are 25 primes in the range of 2 and 100 DISCUSSION 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 READ is 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, EXIT and 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. FINDING ALL PRIME FACTORS OF A POSITIVE INTEGER PROBLEM STATEMENT As we have learned in high school, any positive integer can be factorized into prime factors. For example, 586390350 can be factorized as follows: 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 :: Input INTEGER :: Divisor INTEGER :: Count WRITE(*,*) 'This program factorizes any integer >= 2 --> ' READ(*,*) Input 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 ! now we only worry about odd factors DO ! 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 Click here to download this program. PROGRAM INPUT AND OUTPUT If the input is 100, the output consists of four factors 2, 2, 5 and 5. This program factorizes any integer >= 2 --> 100 Factor # 1: 2 Factor # 2: 2 Factor # 3: 5 Factor # 4: 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 # 1: 2 Factor # 2: 2 Factor # 3: 2 Factor # 4: 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 Factor # 3: 5 Factor # 4: 5 Factor # 5: 7 Factor # 6: 7 Factor # 7: 13 Factor # 8: 17 Factor # 9: 19 Factor # 10: 19 DISCUSSION 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 Divisor cannot evenly divide Input or Input is 1, we exit the loop. The former condition states that Divisor is not a factor of Input, while the latter means Input is 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 Input will 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 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. HANDLING END-OF-FILE: THE READ STATEMENT REVISITED In many situations, you really do not know the number of items in the input. It could be so large to be counted accurately. Consequently, we need a method to handle this type of input. In fact, you have encountered such a technique in Programming Assignment 1 in which a keyword IOSTAT= was used in a READ statement. The following is its syntax: INTEGER :: IOstatus READ(*,*,IOSTAT=IOstatus) var1, var2, ..., varn The third component of the above READ is IOSTAT= followed by an INTEGER variable. The meaning of this new form of READ is simple: After executing the above READ statement, the Fortran compiler will put an integer value into the integer variable following IOSTAT=, IOstatus above. Based on the value of IOstatus, we have three different situations: 1. If the value of IOstatus is zero, the previous READ was executed flawlessly and all variables have received their input values. This is the normal case. 2. If the value of IOstatus is positive, the previous READ has encountered some problem. In general, without knowing the system dependent information, it is impossible to determine what the problem was. However, if hardware and I/O devices are working, a commonly seen problem would be illegal data. For example, supplying a real number to an integer variable. If IOstatus is positive, you cannot trust the values of the variables in the READ statement; they could all contain garbage values, or some of them are fine while the others are garbage. 3. If the value of IOstatus is negative, it means the end of the input has reached. Under this circumstance, some or all of the variables in the READ may not receive input values. What is the end of file? How do we generate it? If you prepare your input using a file, when you save it, the system will generate a special mark, called end-of-file mark, at the end of that file. Therefore, when you read the file and encounter that special end-of-file mark, the system would know there is no input data after this mark. If you try to read passing this mark, it is considered as an error. If you prepare the input using keyboard, hiting the Ctrl-D key would generate the end-of-mark under UNIX. Once you hit Ctrl-D, the system would consider your input stop at there. If your program tries to read passing this point, this is an error. However, with IOSTAT=, you can catch this end-of-file mark and do something about it. A commonly seen application is that let the program to count the number of data items as will be shown in examples below. EXAMPLES 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 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 READ is executed, io would receive a positive number and the above program exits the DO-loop. COMPUTING ARITHMETIC, GEOMETRIC AND HARMONIC MEANS: REVISITED PROBLEM STATEMENT The arithmetic mean (i.e., average), geometric mean and harmonic mean of a set of n numbers x1, x2, ..., xn is defined as follows: 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 :: X REAL :: Sum, Product, InverseSum REAL :: Arithmetic, Geometric, Harmonic INTEGER :: Count, TotalValid INTEGER :: IO ! this is new variable Sum = 0.0 Product = 1.0 InverseSum = 0.0 TotalValid = 0 Count = 0 DO 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(*,*) '# of items read --> ', Count WRITE(*,*) '# of valid items -> ', TotalValid WRITE(*,*) 'Arithmetic mean --> ', Arithmetic WRITE(*,*) 'Geometric mean --> ', Geometric WRITE(*,*) 'Harmonic mean --> ', Harmonic ELSE WRITE(*,*) 'ERROR: none of the input is positive' END IF END PROGRAM ComputingMeans Click here to download this program. PROGRAM INPUT AND OUTPUT The input consists of a number of real values, one on each line. The program will count the number of input data items and ignore those illegal ones. If the input data is 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 item 1 --> 1. Input item 2 --> 2. Input item 3 --> 3. Input item 4 --> 4. Input item 5 --> 5. Input item 6 --> 6. # of items read --> 6 # of valid items -> 6 Arithmetic mean --> 3.5 Geometric mean --> 2.99379516 Harmonic mean --> 2.44897938 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 --> 10 # of valid items -> 6 Arithmetic mean --> 4.66666651 Geometric mean --> 3.68892741 Harmonic mean --> 2.72236228 DISCUSSION 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. THE DO-CYCLE CONSTRUCT AND A PROGRAMMING EXAMPLE In parallel with the DO-EXIT construct, Fortran has a DO-CYCLE construct as follows: DO control-info statements-1 CYCLE statements-2 END DO where control-info is empty if the loop is a DO-END DO; otherwise, control-info contains all information that a counting DO should have. When the execution of a DO-loop encounters the CYCLE statement, the DO-loop starts next iteration immediately. This is not a recommended feature. So, if it is possible, do not use it. EXAMPLES 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 ! the digits INTEGER :: RED, FOR, DANGER ! the constructed values INTEGER :: Count ! solutions count WRITE(*,*) 'This program solves the following puzzle:' WRITE(*,*) WRITE(*,*) ' RED' WRITE(*,*) 'x FOR' WRITE(*,*) '-------' WRITE(*,*) ' DANGER' WRITE(*,*) Count = 0 DO R = 1, 9 DO E = 0, 9 IF (E == R) CYCLE 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 + E*10 + R 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 Click here to download this program. PROGRAM OUTPUT The following is the output generated by the above program. There are two solutions: This program solves the following puzzle: RED x FOR ------- DANGER Solution 1: RED = 321 FOR = 563 DANGER = 180723 Solution 2: RED = 481 FOR = 364 DANGER = 175084 DISCUSSION 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.