Lecture 6 16
Questions:
· Is it important to check program output?
· Is it important to know what the computer is doing?
· How do I determine what is wrong with my program when I can see from the output that the program logic (or something) is wrong?
Consider the factorial program you did for Lab 1. It has many problems with it that you may or may not have noticed. A sample output is given below:
N = 1 N factorial = 1
N = 5 N factorial = 120
N = 10 N factorial = 3628800
N = 11 N factorial = 39916800
N = 12 N factorial = 479001600
N = 13 N factorial = 1932053504
N = 14 N factorial = 1278945280
N = 15 N factorial = 2004310016
N = 16 N factorial = 2004189184
N = 17 N factorial = -288522240
N = 18 N factorial = -898433024
N = 19 N factorial = 109641728
1 7 1 2 3 4 5 6 7
0 0 0 0 0 0 0
PROGRAM Factorial
! This program calculates factorials of any number N from 1 to 19
CHARACTER (1)::ans
INTEGER::n,i,nfact
10 PRINT *, "Enter the value of N:"
READ *, n
OPEN (unit=10,file='factorial.dat')
IF (n.lt.20) THEN
nfact=1
DO i=1,n
nfact=nfact*i
END DO
PRINT *, "N =", n, " N factorial =",nfact
PRINT *, "do you wish to do another case? Enter Y or N."
WRITE (10,50) n,nfact
50 FORMAT (5x,"N = ", I2, " N factorial = ",I12)
READ *,ans
IF (ans.eq."Y") go to 10
STOP
ELSE
PRINT *, "N must be less than 20. Try again."
GO TO 10
END IF
END
What do you notice from the output?
· If I take the known solutions for n! (i.e., I use a test case for which I know the answer), I quickly conclude that the results above are wrong when n reaches 13. You don’t even have to know what the right answer; you can see something is wrong by looking at the pattern of the results! Thus, the use of test cases with known solutions is mandatory for code verification.
· So what is wrong with the program? We have to know what the computer does when it executes a program. In this case, we know that for 32 bit computers, the largest number that can be handled is 231-1. Arithmetic operations with integers larger than this produces inconsistent results.
· What would have happened if I used this faulty algorithm in some calculations within a Fortran program but had not taken the time to print some results of the factorial calculation? Disaster! Garbage! Without thorough checking of the logic, knowing what the computer does; the only way to debug and verify a program is with ample program output. Use PRINT statements to debug your code and print out intermediate results. It is the only way you will know what is happening when you suspect an error.
Formatted Input/Output
Up to this point, we have looked at simple list-directed (or unformatted) input and output statements:
READ *, input-list
PRINT *, output-list
We now consider more general Fortran statements that allow more control over the way things are printed or input. These are called formatted input and output statements. We will associate a format statement with each read or print (or write) that allows definition of the type of variable being printed or input, spacing within a line of output or input, spacing between lines, etc. We will also define procedures for printing (writing) to a file or reading from a file.
Formatted Output
The general form of a formatted print statement is given by
PRINT format-specifier , output-list
Note the comma (,) in front of the output list. The format-specifier is one of the following:
1. * (an asterisk)
2. A character constant or a character variable (or expression or array) whose value (or contents) specifies the format of the output.
3. The label (same as statement number) of a FORMAT statement.
Each execution of the PRINT statement displays (prints) the values of the items in the output-list on a new line. If the output-list is omitted (along with the comma in front of it), a blank line is printed.
The format-specifier defines how the output is to look. These are described below.
1. An asterisk (*) means to default to list-directed output in which case the items in the output-list are printed in a way that the machine deems best; i.e., you have very little control over the format or “look” of the output.
2. The second type provides formatting information as a character string that consists of format descriptors, separated by commas and enclosed in parenthesis:
‘(list of format descriptors)’
or “(list of format descriptors)”
3. The third option provides the formatting information within a FORMAT statement whose label (statement number) is specified. The FORMAT statement has the general form:
label FORMAT ( list of format descriptors )
where label is an integer in the range 1 to 99999 (same as a statement number). All statement numbers must be unique.
There are many, many format descriptors available. We will discuss the ones that are useful in most engineering applications.
Format Descriptors
Notation:
w = field width; number of columns used to print the number
d = numnber of decimal digits to use in printing
n = multiplier
c = column number
Format descriptor data type example
Iw integer variable I7
Fw.d real variable F10.5
Ew.d real variable E15.5
ESw.d real variable (scientific) ES15.5
ENw.d real var. (engineering) EN20.3
Gw.d general (most anything) G13.4
A or Aw character variable A5
“ ” character string “velocity (fps)”
Lw logical variable L8
Tc tab T20
nX horizontal spacing 10X
/ vertical line spacing /// or 3(/)
In some compilers, the first column of output is reserved for “printer control characters” that control line spacing as follows:
blank normal spacing; advance to next line before printing
0 (zero) double spacing; skip one line before printing
1 advance to top of next page before printing
+ overprint the last line printed
Generally, these printer control characters only work on large centralized printers in which printer control characters have been enabled. When the printer control characters are enabled, the printer does not actually print the control character (only “uses” it). The generally have no effect when the output is directed to a desktop laser printer or to a file.
Good programmers make it a habit to never print in column 1 except when they know what their particular printer will do with the information in column 1. The first format descriptor in the format list is thus 1X so that column 1 is skipped and printing begins in column 2.
Repetition of format descriptors
· Format descriptors (some people call them format codes) may have an integer in front of them to indicate the number of times the format descriptor should be repeated (a repetition factor). For example:
3I7 is the same as I7,I7,I7
and implies the printing of 3 INTEGER variables.
· Parenthesis may be used to indicate repetition or grouping. For example:
2(I5,2F10.2) is the same as I5,2F10.2, I5,2F10.2
and is same as I5,F10.2,F10.2, I5,F10.2,F10.2
which all imply to print 1 INTEGER variable, then 2 REAL variables, then 1 INTEGER variable, then 2 REAL variables
· Use repetition and parenthesis to simplify writing and reading formats.
Integer Output – I format
Iw – print an integer (right justified )
using a field width of w (w columns)
I = 15
J = 2987
PRINT 5, I, J
5 FORMAT (1x, I5, I5)
The format statement could also have been written as
5 FORMAT (1x, 2I5)
The output produced is:
15 2987
------
Note: The alternate form of specifying the format is method 2 where the format codes are placed directly in the PRINT statement:
With a format statement:
PRINT 5, I, J
5 FORMAT (1x, I5, I5)
Without a format statement:
PRINT “(1x, I5, I5)”, I, J
Most good programmers do not use method 2. It looks messy and is hard to read. In addition, when a FORMAT statement is used, it may be used by other PRINT statements which require the same format code(s).
Questions – What happens when …… ?
· What happens if more format descriptors are present in the FORMAT statement then items to print? For example
PRINT 31, I, J
31 FORMAT (1X, 5I5)
Answer: The un-needed format codes are ignored.
· What happens if there are more items to be printed then there are format codes provided? For example
I = 15; J = 2987; K = -250; L = 0; M = 37
PRINT 28, I, J, K, L, M
28 FORMAT (1X, 2I5)
Answer: It depends!
Answer 1: When the end of format descriptor list is reached (the right parenthesis), the format is applied again and a new line of output is started. Thus, the above produces the following:
15 2987
-250 0
37
------
Answer 2: If the format codes are grouped with parenthesis, the format is repeated by using the format from the right-most left parenthesis. Each repeat starts a new line of output. Suppose we had:
I = 15; J = 2987; K = -250; L = 0; M = 37
PRINT 288, I, J, K, L, M
288 FORMAT (1X, I10,(1X, 2I5))
15 2987 –250
0 37
------
· What happens if the number will not fit into the specified format width (the field width, or number of columns allowed)? For example
I = 5; J = 987; K = -2999
PRINT 439, I, J, K
439 FORMAT (1X, 3I4)
Answer: The field is filled with asterisks (*). For the above, the output will be:
5 987****
------
Real Output – F, E, ES and EN format
· The value is right justified in the field width w using d decimal digits. The real value is always rounded (up or down in standard manner) to obtain d decimal digits for printing (nothing happens to number in computer)
· If there are less than d decimal digits in the value, the remaining position are filled with zeros.
Examples of each real format:
Fw.d
X = 5.0; Y = 423.787
PRINT 10, X, Y
10 FORMAT (1X, 2F7.2)
5.00 423.79
------
Consider 3 different formats:
X = 385.72
PRINT 18, X
18 FORMAT (1X, F6.3) prints ******
but
18 FORMAT (1X, F7.3) prints OK
but
18 FORMAT (1X, F12.3) prints OK
Consider:
X = 0.32, Y=0.32
PRINT 25, X, Y
25 FORMAT (1X, F10.1, F10.0)
0.3 0.0
------
In the above case, Y (=0.32) is printed as zero because of the F10.0 format!
Ew.d
X = 5.0; Y = 423.787
PRINT 10, X, Y
10 FORMAT (1X, 2E12.4)
0.5000E+01 0.4238E+03
------
The Ew.d format is always printed using the following style:
Note that 1 column is needed for the sign of the number, 2 columns for the “0.”, 1 column for the “E”, 1 column for the sign of the exponent, and 2 columns for the exponents (a total of 7 columns). Thus, if you want to print d decimal digits, the field width w must be specified as d+7 or greater:
in Ew.d format
If you violate the rule above, or the exponent has more than 2 digits (in single precision), the output field will be filled with asterisks (*).
If you are completely unaware as to the magnitude of the numbers you will be printing, it is always safer to use E format. For example, suppose the number to be printed can be between 10-15 and 10+15. If you use an F format, you would have to use something like
25 FORMAT (1X, F40.20)
just to be sure the number will fit whether it a small or large number. The printed number will take 40 columns and be very hard to read. Alternately, you can use an E format such as
25 FORMAT (1X,E15.7)
and the number will always print regardless of its magnitude (unless it exceeds machine capacity). Of course, some people don’t like the “look” of an E format. You make the choice……..
ESw.d (scientific notation) – output is normalized so mantisa (part of
number in front of decimal is between 1 and 10
X = 5.0; Y = 423.787
PRINT 30, X, Y
30 FORMAT (1X, 2ES12.4)
5.0000E-00 4.2379E+02
------
in ESw.d format
ENw.d (engineering notation) – output is normalized so exponent is
multiple of 3 (or mantissa is greater than 1 and less than 1000)
X = 5.0; Y = -423.787; Z=0.0012
PRINT 40, X, Y,Z
40 FORMAT (1X, 3EN13.4)
5.0000E-00-423.7870E+00 1.2000E-03
------
in ENw.d format
Character Output
Character strings are placed within quotes in the FORMAT statement.
X = 10.2
PRINT 123, X
123 FORMAT (1X, "X = ", F10.3)
X = 10.200
------
Positioning in a Line of Output - X and T format