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