362 25 3MB
English Pages 286 Year 1994
Introduction to Fortran 90 for Scientists and Engineers
Índice: Cap 1 - Getting Going:
5
Cap 2 - Chapter 2 Elementary Fortran: I:
8
Cap 3 - Chapter 3 Elementary Fortran: II:
24
Cap 4 - Chapter 4 Program Preparation:
41
Cap 5 - Chapter 5 Decisions:
47
Cap 6 - Chapter 6 Loops:
58
Cap 7 - Chapter 7 Errors:
80
Cap 8 - Chapter 8 Subprograms and Modules:
86
Cap 9 - Chapter 9 Arrays:
108
Cap 10 - Chapter 10 Advanced Input and Output:
126
Cap 11 - Chapter 11 Handling Characters:
141
Cap 12 - Chapter 12 Derived Types: Structures:
152
Cap 13 - Chapter 13 Pointer Variables:
171
Cap 14 - Chapter 14 Simulation:
186
Cap 15 - Chapter 15 Matrices and Their Applications:
197
Cap 16 - Chapter 16 Introduction to Numerical Methods: 224 App B - Appendix B Summary of Fortran 90 Statements:248 App C - Appendix C Intrinsic Procedures:
265
App D - Appendix D ASCII Character Codes:
273
App E - Appendix E Solutions to Selected Exercises:
274
1
Introduction to Fortran 90 for Scientists and Engineers An easy to use online version of "Fortran 90 for Scientists and Engineers," by Brian Hahn, is provided with Fortran PowerStation 4.0 for your use. If you find this book helpful, and would like a paper copy, an order form has been provided. You can either print the order form and mail it to the address provided, phone in your order, or use email to order the book.
Fortran 90 for Scientists and Engineers Brian D Hahn
Department of Applied Mathematics
University of Cape Town
Hahn, Brian D Fortran 90 for Scientists and Engineers I. Title 005.13 ISBN 0-340-60034-9 All rights reserved. No part of this publication may be reproduced or transmitted in any form or by any means, electronically or mechanically, including photocopying, recording or any information storage or retrieval system, without either prior permission in writing from the publisher or a licence permitting restricted copying. In the United Kingdom such licences are issued by the Copyright Licensing Agency: 90 Tottenham Court Road, London WIP 9HE Whilst the advice and information in this book is believed to be true and accurate at the date of going to press, neither the author nor the publisher can accept any legal reaponsibility or liability for any errors or omissions that may be made. Printed and bound in Great Britain for Edward Arnold, a division of Hodder Headline PLC, 338 Euston Road, London NW1 3BH, by the University Press, Cambridge
Foreword The present text arises from an extensive revision of our previous book {Advanced Methods of Data Exploration and Modelling}. Since so much new material is included, particularly in those sections dealing with linear models and latent variable models, we thought it appropriate to regard the work as new rather than simply a second edition. Consequently we have taken the opportunity to give the book a more appropriate title.
Preface The Fortran 90 standard represents the first significant change in Fortran in over 20 years, and brings it into line with most modern structured programming languages. This book is one of a handful on Fortran 90, and one of even fewer in which every program (unless otherwise clearly stated) has been tested on a working compiler: the FTN90 compiler for PCs. If you are a newcomer to Fortran, you should read the book in the conventional way, from the beginning. However, if you are a Fortran 77 user you may like to dip immediately into later chapters to see some of the new features of the language. Probably the two most important advances are the new array facilities (Chapters 9 and 15) and the impressively enlarged collection of intrinsic procedures (Appendix C), including the so-called elemental functions which operate on all or selected elements of array arguments. You may now define your own types, or structures (Chapter 12) and even construct linked lists with them using pointers (Chapter 13). Modules (Chapter 8) may be independently compiled, and may contain type definitions and variable declarations, as well as procedures. The use of interface blocks (Chapter 8) makes it possible to overload specific procedure names with generic names, and also to overload operators. Conditional loops are possible now with DO WHILE (Chapter 6), and there is a new CASE statement (Chapter 6). However, you should
2
probably first have a look at Sections 2.2--2.5 (program layout, variable declarations, etc.) and Section 3.5(kind) to see some important changes in the basics of Fortran. In keeping with the spirit of the earlier edition, this book is a problem-solving exposition of Fortran 90, and not a technical reference manual. You will therefore not necessarily find all the references to a particular topic in one place in the text (e.g.\ arrays are covered in Chapters 9 and 15) as this would interfere with the informal style of the book. There are, however, appendices with summaries of all the statements and the intrinsic procedures, and a comprehensive index. I should like to thank the following in particular: David Mackin of Edward Arnold for his helpful editorial suggestions, and for arranging the loan of an FTN90 compiler; Peter Anderton of The Numerical Algorithms Group for the loan of the compiler; the University of Cape Town for leave in order to write this book, and for financial support for the project; my long-suffering colleagues for leaving me alone while I was writing; and my wife, Cleone, who patiently reminds me when programs won't work, that computers are like that, aren't they? Brian D. Hahn Department of Applied Mathematics University of Cape Town Rondebosch South Africa June 1993
Preface to Problem Solving with FORTRAN 77 So many books on FORTRAN have been written that the appearance of yet another one seems to require some justification. There are three particular areas where this book can claim to make a distinctive contribution. Firstly, the approach taken is a problem-solving one, developed over many years of teaching programming to first-year university students with no computing experience. The computer is presented as a tool (probably the most exciting one of the 20th century) for solving interesting, real world problems, and examples from many areas, particularly science and engineering, are discussed. The technicalities of each new FORTRAN construction are therefore generally presented only after motivation by the posing of a suitable problem. Since the objective of this book is to enable you to solve problems using a computer, the first 12 chapters are in a sense a preparation for the final three. In these later chapters you will be introduced to some modern computer applications such as simulation, modelling and numerical methods. There are also a large number of exercises, involving a variety of applications. Most of these have solutions provided. Those that do not have solutions may be suitable for use as class projects in a teaching situation. Secondly, structured problems are developed throughout. The beginner is shielded from the devastating effect of the GOTO statement until well into the text. When it is introduced, the use of GOTO is encouraged in one well-defined situation only: this feature appears to be unique in all the vast literature on FORTRAN. Thirdly, emphasis is laid throughout the book on what has come to be called programming style, and guidelines for writing clear, readable programs are presented. This book has developed out of notes originally written as a supplement to lectures for students taking courses in applied mathematics at the University of Cape Town, with no prior experience of computing. It can therefore be used as a ``teach yourself" guide by anyone who wants to learn FORTRAN 77 (officially known as FORTRAN ANSI X3-9 1978), the current international standard, which is the version used here. Although this is primarily a text for beginners, the more experienced programmer should be able to find plenty of interest, particularly in the applications. He may even learn something! The appendices contain summaries of all the FORTRAN 77 intrinsic functions and
3
statements (including those which are not recommended for stylistic reasons), with examples of their general usage. No specialized mathematical background is needed to follow most of the examples. There are occasional forays into first-year university mathematics, but these are self-contained and may be glossed over without loss of continuity (you may even find them instructive!). Thanks are due to John Newmarch of the University of Cape Town Information Technology Services for his critical reading of the original manuscript on which this book is based, and for his invaluable suggestions regarding programming style. Thanks are also due to the generations of students who have patiently endured my efforts to improve my methods of teaching computing. I also wish to thank my colleague, Ruth Smart, who collaborated with me on an earlier version of this book, for her helpful advice and painstaking reading of the manuscript. Finally, I should like to acknowledge a deep debt of gratitude to my wife, Cleone, for her continual support and encouragement during the preparation of this book. It is hoped this book will give some insight into the ways that computers may be used to solve real problems, and that after working through it you will be better able to find out more about this fascinating subject for yourself.
Epilogue Programming Style Throughoutthis bookthe emphasis has been on writing clear,coherent programsto solve interesting problems. A program whichis written any old how, although it may do whatisrequired,is goingto be difficultto understand when you go through it again after a month or two. Serious programmers therefore pay a fair amount of attention to whatis called programming style,in orderto make their programs clearer and more readable both to themselves, and to other potential users. You may find this irritating, if you are starting to program for the first time, because you will naturally be impatient to get on with the job. But a little extra attention to your program layout will pay enormous dividends inthe long run, especially when it comes to debugging. Some hints on how to improve your program ming style are given below.
•
• • • • • • •
•
•
•
4
You should make liberal use of com m ents, both at the beginning of a program unit or subprogram,to describe briefly whatit does and any special methodsthat may have been used, and also throughout the coding to introduce differentlogical sections. Any restrictions on the size and type of datathat may be used as input should be stated clearly in the com m ents (e.g. maximum sizes of arrays). The meaning ofeach variableshould be described brieflyin a com ment atits declaration. You should declare variables systematically, e.g.in alphabeticalorder by type. Subprograms should be arranged in alphabetical order with at least one blank line between them. Blank lines should be freely used to separate sections of coding (e.g. before and after loop structures). Codinginside structures(loops, decisions,etc)should beindented a few columnsto makethem stand out. Blanks should be used in statements to make them more readable, e.g. on either side of operators and equal signs; after commas However,blanks may be omittedin placesin complicated expressions, wherethis may makethe structure clearer. FORMAT statements should be grouped together. The GOTO statement should never be used, under any circumstances. You should try to avoid breaking out of structuresinthe middle, e.g. with CYCLE or EXIT. Statements which generate an obsolescence warning should be avoided —they could well disappear during revision forthe next standard.
Chapter 1 Getting Going 1.1. Introduction 1.2. Fortran 1.3. Running Fortran Programs
•
• •
Greetings AIDS cases Compound interest
Chapter 1 Summary Chapter 1 Exercises
1.1. Introduction In the period since I first became an undergraduate student, some 25 years ago, I have been fortunate enough to witness the remarkable revolution in computer technology which future historians will surely regard as one of the outstanding features of the twentieth century. The first computer I programmed occupied a large room. Only one person could use it at a time, by pressing an impressive array of switches, and programs had to be punched on cards. Its "fast" memory could store about 240 numbers. Its slow memory could hold a few thousand numbers, and was located on a rotating drum which you could hear ticking as it spun. As technology advanced, and computers became more powerful, they also became much smaller. From occupying a whole room, they now only require part of a desk, a lap, or even a palm. They have banded together to form networks, and during an average working day, it is not uncommon to send electronic mail messages around the world, and to connect directly to a computer on the other side of the world. You may not have used a computer before (except possibly to play games) but you are probably familiar with using a calculator. The simplest sort can only do arithmetic and display an answer. Smarter ones have memory locations—where intermediate results may be stored—and function keys such as sin, log, etc. The most sophisticated calculators allow you to store the sequence of operations (instructions) needed to calculate the solution of the problem. This sequence of instructions is called a program. To carry out the entire set of calculations you only need to load the program into the calculator, press the run key, supply the necessary data, and sit back while the calculator churns out the answer. A computer, whether it is a small personal one like the IBM PC, or a large impersonal mainframe, is in principle only an advanced programmable calculator, capable of storing and executing sets of instructions, called programs, in order to solve specific problems. You may have used a computer before, but only to run software packages that have been written by someone else. Spreadsheets, databases and word processors fall into this category. If you have taken the trouble to start reading this book, you probably have an interest in science or engineering, and are curious enough about programming to want to write your own programs to solve your particular problems, instead of relying on someone else's more general package.
1.2. Fortran The particular set of rules for coding the instructions to a computer is called a programming language. There are many such languages, for example Fortran, BASIC, Pascal and C++. Fortran, which standsfor FOR mula TRA Nslation, wasthe first"high level" programming language.It made it possible to use symbolic names to represent mathematical quantities,and to write mathematical formulae in a reasonably comprehensible form, such as X = B/(2*A). The idea of Fortran was proposedinlate 1953 by John Backus,in New York,and the first Fortran program was run in April 1957.
5
The use of Fortran spread so rapidly that it soon became necessary to standardize it, so that a program written in the standard would be guaranteed to run at any installation which claimed to support the standard. In 1966 the first ever standard for a programming language was published. This version became known as Fortran 66 (more correctly FORTRA N 66, but the practice of capitalizing acronyms is becoming unfashionable). A new standard, Fortran 77, was published in 1978. In spite of competition from newer languages such as Pascal and C, Fortran continued to flourish, so much so that the latest standard, Fortran 90, came out in August 1991. This is the version used in this book. Connoisseurs of Fortran will be interested in the history of the language sketched by Michael Metcalf and John ReidMetcalf and Reid in Fortran 90 Explained, Oxford University Press (Oxford, 1990). If you are already experienced in Fortran, you might like to consultthe Preface, which indicates wherethe new features may be found. You willalso need to know thatsome old features have been declared obsolescent. These (which may include some of your old favourites) have been made redundant by the new standard, and are recommended for deletion in the next standard, i.e. the recommendation is not binding. Appendix B contains a sum mary of all Fortran 90 statements,and indicates which are obsolete and/or notrecom mended.
1.3. Running Fortran Programs If you are new to Fortran, you should run the sample programs in this section as soon as possible, without trying to understand in detail how they work. Explanations will follow in due course. You will need to find out, from a manual or from someone else, how to enter and run Fortran programs on your computer system.
Greetings This program will greet you if you give it your name: ! My first Fortran 90 program! ! Greetings! CHARACTER NAME*20 PRINT*, 'What is your name?' READ*, NAME PRINT*, 'Hi there, ', NAME END You should getthe following output (your response isinitalics): W hat is your name? Garfield Hi there, Garfield
AIDS cases The following program computesthe number of accumulated AIDS cases A(t)inthe United States in year t according to the formula
A(t ) = 174.6(t − 19812 . )3
PROGRAM AIDS ! Calculates number of accumulated AIDS cases in USA INTEGER T ! year REAL A ! number of cases READ*, T A = 174.6 * (T - 1981.2) ** 3 PRINT*, 'Accumulated AIDS cases in US by year', T, ':', A END PROGRAM AIDS
6
If you supply the value 2000 forthe year you should getthe output Accumulated AIDS cases in US by year 2000 :
1.1601688E+06 6
The answeris given in scientific notation. E+06 means multiplythe preceding number by 10 ,so the number of casesis about 1.16 million. Using trial and errorrun the program repeatedly to find out when there will be about10 million accumulated cases. Try typing a mistake inthe value of t (2,000 for example)to see how Fortran responds.
Compound interest Suppose you have $1000 saved in the bank, which compounds interest atthe rate of 9% per year. W hat will your bank balance be after one year? You must obviously be able to do the problem in principle yourself,ifyou wantto program the computerto doit. Thelogicalbreakdown, or structure plan, ofthe problem is as follows: 1. 2. 3. 4.
Get the data (initial balance and interestrate)into the computer Calculatethe interest(9% of $1000,i.e. $90) Add the interesttothe balance ($90 + $1000, i.e. $1090) Print(display) the new balance.
Thisis how the program looks: PROGRAM MONEY ! Calculates balance after interest compounded REAL BALANCE, INTEREST, RATE BALANCE = 1000 RATE = 0.09 INTEREST = RATE * BALANCE BALANCE = BALANCE + INTEREST PRINT*, 'New balance:', BALANCE END PROGRAM MONEY Run the program and notethatnoinput(from the keyboard)isrequired now (why not?). The output should be 1.0900000E+03 (1090).
Summary •
•
•
A computer program is a setof coded instructions for solving a particularproblem. The Fortran statement READ* isfor getting datainto the computer. The Fortran statement PRINT* isfor printing (displaying) results.
Chapter 1 Exercises 1.1 Writea program to computeand printthesum, difference,productand quotientoftwo numbers A and B (supplied from the keyboard). The symbols for subtraction and division are - and / respectively. Use the program to discover how Fortran reactsto an attempted division by zero. 2
1.2 The energy stored on a condenseris, CV / 2 w here C isthe capacitance and V isthe potential difference. Write a program to compute the energy for some sample values of C and V. Solutions to most exercises are in Appendix E.
7
Chapter 2 Elementary Fortran: I Chapter 2 Introduction 2.1. Compound Interest Again 2.2. Program Layout •
•
Statements
•
Com ments
•
Significance of blanks Continuation lines
2.3. Data Types 2.4. Literal Constants
•
•
•
Bits'n bytes Integerliteral constants Realliteral constants
2.5. Names and Variables •
Implicittype rule
2.6. Vertical Motion under Gravity 2.7. Programming Style 2.8. Numeric Expressions
•
•
Integer division Mixed-mode expressions
2.9. Numeric Assignment •
Examples
2.10. Simple Input and Output •
•
Input
•
Reading data from textfiles
•
Example
•
Output Sending output tothe printer
Chapter 2 Summary Chapter 2 Exercises
8
Chapter 2 Introduction In this chapter and the next one we willlook in detail at how to write Fortran programs to solve simple problems. There aretwo essentialrequirements forsuccessfully mastering this art: •
•
The exactrules for coding instructions mustbe learnt; A logical plan for solving the problem mustbe developed.
These two chapters are devoted mainly to the firstrequirement:learning some basic coding rules. Once you have mastered these, we can go on to more substantial problems. All Fortran 90 statementsintroduced in thisand subsequent chapters(and some which are not) are summarized in Appendix B.
2.1. Compound Interest Again In Chapter 1 you ran the program MONEY to compute compound interest: PROGRAM MONEY ! Calculates balance after interest compounded REAL BALANCE, INTEREST, RATE BALANCE = 1000 RATE = 0.09 INTEREST = RATE * BALANCE BALANCE = BALANCE + INTEREST PRINT*, 'New balance:', BALANCE END PROGRAM MONEY We will now discuss in detail how the program works. W hen you run a Fortran 90 program two separate processes take place. Firstly the program is compiled. This means that each statement is translatedinto some sortof machine code thatthe computercan understand. Secondly,the compiled program is executed.Inthisstep eachtranslatedinstructionis carried out.The software packagethat carries out both these processes is generally called a compiler. During compilation, space in the computer's random access memory (RA M) is allocated for any numbers(data) which willbe generated by the program. This partofthe memory may bethought of as a bank of boxes, or memory locations, each of which can hold only one number at atime. These memory locations are referred to by symbolic names inthe program. So the statement BALANCE = 1000 allocates the number 1000 to the memory location named BALANCE. Since the contents of BALANCE may change during the program itis called a variable. The translated (compiled) form of our program looks roughly as follows: 1. Putthe number 1000 into memory location BALANCE 2. Putthe number 0.09 into memory location RATE 3. Multiply the contents of RATE by the contents of BALANCE and putthe answer in INTEREST 4. Add the contents of BALANCE to the contents of INTEREST and putthe answer in BALANCE 5. Print(display) a message followed by the contents of BALANCE 6. Stop. During execution, these translated statements are carried out in order from the top down. After execution,the memory locations used will have the following values: BALANCE : 1090 INTEREST : 90 RATE : 0.09
9
Note thatthe original contents of BALANCE islost. The PROGRAM statement in the first line introduces the program. It is optional, and may be followed by an optional name.The secondline,starting with an exclamation mark,isa com mentfor the benefit of the reader, and has no effect on the compilation. Variables in a program can be of different type; the REAL statement declarestheirtypeinthisexample. Thefirstthree non-blanklines ofthis program are non-executable,i.e.no actionis carried out bythem (they have no counterpartin the translated form ofthe program above). Try the following exercises: 1. Run the program. 2. Change the first executable statement to read BALANCE = 2000 and make sure that you understand what happens when you run the program again. 3. Leave out the line BALANCE = BALANCE + INTEREST and re-run. Can you explain what happens? 4. Try to rewritethe program so thatthe originalcontents of BALANCE is not lost. A number of questions have probably occurred to you by now, such as
•
•
•
•
W hat names may be used formemory locations? How can numbers be represented? W hat happens if a statement won'tfit on one line? How can we organize the output more neatly?
These questions, and hopefully many more,will be answered in the following sections.
2.2. Program Layout The general structure of a simple Fortran program is as follows (items in square brackets are optional): [PROGRAM program name] [declaration statements] [executable statements] END [PROGRAM [program name]] As you can see,the only compulsory statementin a Fortran program is END. Thisstatementinforms the compilerthatthere are no further Fortran statementsto compile. The notation END [PROGRAM [program name]] meansthatthe program name may be omitted from the END statement,butthatifthere isa program name,the keyword PROGRAM may not be omitted.
Statements Statements form the basis of any Fortran program, and may contain from 0 to 132 characters (a statement may be blank; blank statements are encouraged to make a program more readable by separatinglogicalsections). Earlier versions of Fortraninsistedthatcertain parts of a statementstart in certain columns; Fortran 90 has no such restriction. All statements,except the assignment statement (e.g. BALANCE = 1000), start with a keyword. Some keywords encountered so far are END, PRINT, PROGRAM, and REAL. Generally,there willbe one statement perline. However, multiplestatements may appearon alineif they are separated by semi-colons. Forthe sake of clarity,thisisrecom m ended only with very short assignments,such as A = 1; B = 1; C = 1
10
Long statements may continue over severallines as discussed below.
Significance of blanks Blanks are generally not significant, i.e. you can use them to improve readability by indenting statements (adding blanks on the left) or padding within statements. However, there are places where blanks are not allowed. To be specific itis necessary to define atechnicalterm: the token. A token in Fortran 90 is a basic significantsequence of characters, e.g.labels, keywords, names, constants, operators and separators (these items are all discussed later). Blanks may not appear within atoken.So INTE GER, BAL ANCE and < = are notallowed ( = =
) Name, Mark TopMark) THEN Mark Name
PRINT*, 'Top student: ', TopName PRINT*, 'Top mark: ', TopMark W ork through the program by hand for a few turnsto convince yourself thatit works. Try it out on the following sample data (remember the apostrophes, because the names contain commas): "Able, RJ" 40 "Nkosi, NX" 60 "October, FW" 13
ELSE IF Recall the program /Final_Mark/ in Chapter 3. To output the grade (1, 2+, 2--, 3 or F) of each student'sfinalmark we might be tempted to replace the segment IF (Final >= 50) THEN ... END IF with a set of simple IF statements as follows: IF (Final >= 75) PRINT*, Name, CRM, ExmAvg, Final, '1' IF (Final >= 70 .AND. Final < 75) PRINT*, Name, CRM, ExmAvg, Final, '2+' IF (Final >= 60 .AND. Final < 70) PRINT*, Name, CRM, ExmAvg, Final, '2-' IF (Final >= 50 .AND. Final < 60) PRINT*, Name, CRM, ExmAvg, Final, '3' IF (Final < 50) PRINT*, Name, CRM, ExmAvg, Final, 'F' (the logical operator .AND. is explained fully below). W hilethis works,itis inefficient and may waste preciouscomputingtime. There arefive separate IF statements. Thelogicalexpressionsin all five (e.g. Fin >= 75) haveto be evaluated for each student,although we know that only one can betrue;a studentcannot get afirstclass pass and alsofail! The following is a more efficient way of coding the problem. For good measure, we willalso counthow many passed in the firstclass, how many in the second class,and so on. The integer variables Firsts, UpSeconds, LowSeconds, Thirds and Fails representthe number of studentsin each ofthese respective classes. IF (Final >= 75) THEN PRINT*, Name, CRM, ExmAvg, Final, '1'
49
Firsts = Firsts + 1 ELSE IF (Final >= 70) THEN PRINT*, Name, CRM, ExmAvg, Final, UpSeconds = UpSeconds + 1 ELSE IF (Final >= 60) THEN PRINT*, Name, CRM, ExmAvg, Final, LowSeconds = LowSeconds + 1 ELSE IF (Final >= 50) THEN PRINT*, Name, CRM, ExmAvg, Final, Thirds = Thirds + 1 ELSE PRINT*, Name, CRM, ExmAvg, Final, Fails = Fails + 1 END IF
'2+' '2-' '3' 'F'
This saves time because Fortran stops checking as soon asitfinds a true logical expression. So if Final >= 75 istrue,it won'tbotherto check further. The onusrests on you therefore to codethe construct correctly,so that only one ofthe logical expressions istrue. Note also how indentation makes the structure easierto follow.
The IF construct in general A more generalform ofthe IF constructis: IF (logical-expr1) THEN block1 ELSE IF (logical-expr2) THEN block2 ELSE IF (logical-expr3) THEN block3 ... ELSE blockE END IF If logical-expr1 is true the statements in block1 are executed, and control passes to the next statement after END IF. If logical-expr1 is false, logical-expr2 is evaluated. If it is true the statements in block2 are executed, followed by the next statement after END IF. If none of the logical expressions is true,the statements in blockE are executed. Clearly,the logical expressions should be arranged so that only one ofthem can be true at atime. There may be any number ofELSE IFs (or none at all), butthere may be no more than one ELSE. An IF construct may be optionally named as an aid to the reader (usually to clarify complicated nesting), e.g. [GRADE:] IF (Final >= 50) THEN PRINT*, 'Pass' ELSE [GRADE] PRINT*, 'Fail' END IF [GRADE] An ELSE or ELSE IF block may only be named ifthe corresponding IF and END IF blocks are named, and must be given the same name. The name must be a valid and unique Fortran name. Note that nothing may follow the keyword THEN on the firstline ofthe construct.
50
Nested IFs W hen IF constructs are nested,the positioning of the END IFs is crucial, as this determines to which IFs the ELSE IFs belong. An ELSE IF or ELSE belongsto the mostrecently opened IF which has not yet been closed. To illustrate,consider once again program ming the solution of the ubiquitous quadratic equation, ax 2 + bx + c = 0. It is necessary to check if a = 0, to prevent a division by zero: Disc = B * B - 4 * A * C Outer: IF (A /= 0) THEN Inner: IF (Disc < 0) PRINT*, 'Complex ELSE Inner X1 = (-B + SQRT( X2 = (-B - SQRT( END IF Inner END IF Outer
THEN roots' Disc )) / (2 * A) Disc )) / (2 * A)
W hat will happen ifthe END IF Inner is moved up 3 lines as shown below? Outer: IF (A /= 0) THEN Inner: IF (Disc < 0) THEN PRINT*, 'Complex roots' END IF Inner ! Wrong place now! ELSE Inner X1 = (-B + SQRT( Disc )) / (2 * A) X2 = (-B - SQRT( Disc )) / (2 * A) END IF Outer Well,the compiler willobjectbecause of a clash of names: ELSE Inner cannot appear after END IF Inner closes the Inner IF. However, if all the names are omitted, the segment will compile, but will make a division by zero certain if a = 0, since the ELSE will now belong to the first IF---try it. Nesting may extend to any depth;indentation and/or naming should be carefully used in such cases to make the logic clearer.
DOs and IFs A DO loop may contain an IF construct,and vice versa. The basicrule isthatif a construct begins inside anotherconstruct,it must also end inside that construct. The following istherefore illegal: DO I = 1, 10 IF (I > 5) THEN ... END DO ! Illegal: IF must end before DO END IF and so is this: IF ( ... ) THEN DO I = 1, 10 ... END IF ! Illegal: DO must end before IF END DO
5.2. Logical Type So far four of the five intrinsic data types have been discussed: integer, real, character and complex. The time has come to discuss the fourth type: logical.
51
Logical constants The default kind of logical type has two literal constants: .TRUE. and .FALSE. (upper- or lowercase). The value of the default kind parameter is returned in the usual way, by KIND( .TRUE. ) Your compiler may have non-default logical kinds; these may be used, for example, for storing logical arrays more compactly.
Logical expressions We have seen logical expressions briefly in Chapter 3. They can be formed in two ways: from numeric expressions in combination with the six relational operators, or from other logical expressions in combination withlogical variables and the five logical operators. The relational operators and their meanings,with some examples, are as follows: Relational Operator .LT. or < .LE. or .GE. or >=
Meaning
Example
lessthanA < 1e-5 lessthan or equalB ** 2 .LE. 4 * A * C equal B ** 2 == 4 * A * C not equal A /= 0 greaterthan B ** 2 - 4 * A * C > 0 greaterthan orequal X >= 0
Logical operators Fortran 90 has five logical operators, which operate on logical expressions: Logical Operator
Precedence
Meaning
.NOT. 1 logical negation .AND. 2 logicalintersection .OR. 3 logical union .EQV. and .NEQV. 4 logical equivalence and non-equivalence The following "truthtable" shows the effects ofthese operators on the logical expressions lex1 and lex2 (T = true;F = false): lex1 lex2 T T F F
lex2
.NOT. lex1
lex1 .AND. lex2 lex1 .OR. lex2
lex1 .EQV. lex2 lex1
.NEQV.
T F T T T F F F F T F T T T F T F T F T F F T F The order of precedence,shown above, may be superseded with parentheses, which always havethe highest precedence. Examples: (B * B == 4 * A * C) .AND. (A /= 0) (Final >= 60) .AND. (Final < 70) (A /= 0) .or. (B /= 0) .or. (C /= 0) .not. ((A /= 0) .and. (B == 0) .and. (C == 0)) Incidentally,the lasttwo expressions are equivalent, and are false only when A = B = C = 0---it makes you think, doesn'tit?
52
Logical variables A variable may be declared with logical type in a LOGICAL statement. Logical constants or expressions may be assigned to logical variables:
Figure 5.1 Switching circuits
LOGICAL L1, L2, L3, L4, L5 REAL A, B, C ... L1 = .TRUE. L2 = B * B - 4 * A * C >= 0 L3 = A == 0 L4 = L1 .and. .not. L2 .or. L3 L5 = (L1 .and. (.not. L2)) .or. L3 (The precedence rules make L4 and L5 logically equivalent.) The truth values oflogical variables are represented by T and F in list-directed I/O.
Simulation of a switching circuit In the following program segment the logical variables S1 and S2 represent the state of two switches (ON = true; OFF = false) and L representsthe state of a light.The program simulatesthe circuitsin Figure 5.1 where the switches are arranged either in series or parallel. LOGICAL L, S1, S2 READ*, S1, S2 L = S1 .and. S2 !L = S1 .or. S2 PRINT*, L
! series ! parallel
W hen the switches are in series,the light will be on only if both switches are on. This situation is represented by S1.and.S2 W hen the switches are in parallel,the light will be on if one or both of the switches is on. This is represented by S1.or.S2
Bit manipulation functions Some programming languages, such as Pascal and C, have operators, called bitwise operators, which operate directly on the bits of their operands. These are usually discussed in the context of logical (or Boolean) variables. In Fortran 90 their counterparts are the bit manipulation intrinsic functions which operate on the bits of their integer arguments. These are described in Appendix C.
5.3. The CASE Construct The CASE constructis similarto IF. It allows selection between a number of situations or cases, based on a selector.In such cases itis more convenientthan IF. Consider the following program segment:
53
CHARACTER CH DO READ*, CH PRINT*, ICHAR( CH ) IF (CH == '@') EXIT IF (CH >= 'A' .and. CH = 'a' .and. CH FtnNum) THEN PRINT*, 'Too high. Try again' ELSE PRINT*, 'Too low. Try again' END IF WRITE( *, '("Your guess: ")', ADVANCE = 'NO' ) READ*, MyGuess END DO PRINT*, 'BINGO! Well done!' CALL RANDOM_SEED( GET=Seed) ! get the new seed for another game PRINT* PRINT*, 'New seed: ', Seed(1) Try it out a few times. Note thatthe DO loop (which now has no variables or parameters)repeats as long as MyGuess is not equal to FtnNum. There is no way of knowing in principle how many loops will be needed before they are equal,and so this new form of the DO constructis essential here. In this case looping terminates when the statement EXIT is executed. The problem is truly non-deterministic. On reflection,you might feelthe coding is alittle wasteful.The section WRITE( *, '("Your guess: ")', ADVANCE = 'NO' ) READ*, MyGuess hasto appeartwice. Once,tostarttheloop going (or MyGuess would be undefined),and a second time in the loop itself. Change the program asindicated below and try running it(only the section with changes is reproduced): FtnNum = INT( 10 * R + 1) ! remove two lines DO WRITE( *, '("Your guess: ")', ADVANCE = 'NO' ) ! move up READ*, MyGuess ! move up IF (MyGuess > FtnNum) THEN PRINT*, 'Too high. Try again' ELSE IF (MyGuess < FtnNum) THEN ! ELSE IF now PRINT*, 'Too low. Try again' ELSE PRINT*, 'Well done!' ! congrats here now END IF IF (MyGuess == FtnNum) EXIT ! move down END DO ! remove congrats CALL RANDOM_SEED( GET=Seed)
! get the new seed for another game
The equivalent structure plan forthe new version is: 1. Generate random integer 2. Repeat: Ask If Otherwise
user guess Tell if Tell
for is him guess him
too it
is is
it
is
too too too
guess low low high high
Otherwise Polite Until guessis correct
66
congratulations
3. Stop. The essentialdifferenceisthatthe EXIT occurs atthe top ofthe DO block inthefirstversion, but at the end of the block in the second version. There is a more subtle difference, however:in the first case the condition for exiting istested atthe top;inthe second case itis onlytested atthe end.
DO: conditional EXIT We have seen two further versions ofthe DO construct: DO IF (logical-expr) EXIT block END DO and DO block IF (logical-expr) EXIT END DO (both versions may be named). The EXIT statement provides a means to exit from an otherwise endless loop. It may in fact go anywhereintheloop. However,itis bestforitto go eitheratthetop or atthe end;the reader does notthen have to search through the loop to find the exit condition. Some purists might argue that the EXIT should always be at the top of such a non-deterministic loop,sothatitisclearto a reader how a loop willend when she firstencountersit. The while-do constructoflanguageslike Pascallendsitself morereadilytothisconvention. The way Fortran 90 is designed makesit more naturalto putthe EXIT atthe end. However,I am sure you are old enough to decide for yourself! Thereis one situationin which the EXIT must be atthetop oftheloop, and thisis when a zerotrip countislogically possible. An exampleisthe originalform of the guessing game above:ifthe user guesses the number correctly firsttime,there should be no executions ofthe DO block.
DO WHILE A DO construct may be headed with a DO WHILE statement: DO
WHILE (logical-expr) block END DO
Thisislogically equivalentto DO IF (.NOT.logical-expr) EXIT block END DO The DO WHILE is a very compelling construction sincethe condition to repeatis stated clearly at the top of the loop. It may however involve optimization penalties under certain circumstances. There are many examples ofits usage later.
67
DO: variations which are not recommended The EXIT statement may also be used in a DO construct with a DO variable and parameters: DO I = 1, N ... IF (I == J) EXIT ... END DO Thisform is moststrongly notrecom mended! If you aretempted to trythisin orderto get out of a tricky situationit probably means you have notthoughtthrough thelogic clearly enough. You must be ableto stateallthe possible conditionsforan exit unambiguously either atthetop orthe bottom of the loop. Some examples where this situation arises are given below. The statement CYCLE [name] transferscontroltothe END DO statement ofthe corresponding construct,so iffurtheriterations are stillto be carried outthe nextone isinitiated.Its useis notrecommended —it makesthelogic more difficultto see. The DO construct may make use of a statementlabel, as follows: DO 100 I = 1, N ... 100 CONTINUE The CONTINUE is a dum m y statement which does nothing. The construct may also end with a labelled END DO. This form is not recommended —the labels are not necessary and obscure the logic with redundantinformation.
Doubling time of an investment Suppose we haveinvested some money which draws 10% interestper year,compounded. We would liketo know how long ittakesfortheinvestmentto double. More specifically, we want a statement ofthe account each year, until the balance has doubled. The English statement ofthe problem hints heavilythat we should use a non-deterministic DO with the EXIT condition atthe end of the loop. The structure plan and program forthe problem are: 1. 2. 3. 4.
Start Initialize balance, year,rate,interest Write headings Repeat Update balance according Write year, until balance exceeds twice original balance 5. Stop.
to interest,
interest
IMPLICIT NONE INTEGER Year REAL Interest, New, Old, Rate PRINT*, 'Original balance:' READ*, Old Rate = 0.1 New = Old ! keep a copy of the original balance Year = 0
68
rate balance
PRINT*, 'Year PRINT*
Interest
Balance'
DO Interest = Rate * New New = New + Interest Year = Year + 1 PRINT*, Year, Interest, New IF (New > 2 * Old) EXIT END DO The condition New > 2 * Old is checked each time before anotheriteration. Repetition occurs only ifthe condition is true. The DO block must be executed at least once, since you must invest your money foratleasta yearfor anythingto happen. Consequently,the EXIT must be atthe end of the DO. The outputlooks like this(for an opening balance of $1000): Year
Interest
Balance
1 1.0000000E+02 1.1000000E+03 2 1.1000000E+02 1.2100000E+03 ... 7 1.7715611E+02 1.9487172E+03 8 1.9487172E+02 2.1435889E+03 Notethat when thelastiteration has been completed,the conditionto EXIT istrueforthefirsttime, sincethe new balance ($2143.59)is morethan $2000. Note alsothat a deterministic DO cannot be used here because we don'tknow how manyiterations aregoingto be needed untilafterthe program has run (although in this example perhaps you could work outin advance how many iterations are needed?). If you wantto writethe new balance only whileitis less than $2000, allthat has to be done is to move PRINT*, Year, Interest, New untilitisthe firststatementin the DO loop (tryit). Notethatthe starting balance of zero is written now. The EXIT condition can be placed atthe top ofthe original DO block ifitis rephrased as follows: IF (New < 2 * Old) EXIT Note that > has been replaced by 3 is prime IMPLICIT NONE INTEGER :: N = 3 INTEGER P, Rem PRINT*, 'Gimme an odd integer:' READ*, P Rem = MOD( P, N ) DO IF (Rem == 0 .OR. N >= SQRT( REAL(P) )) EXIT N = N + 2 Rem = MOD( P, N ) END DO IF (Rem /= 0) THEN PRINT*, P, ' is prime' ELSE PRINT*, P, ' is not prime' END IF END
− 1 .It has If such things interest you,the largest prime number at the time of writing is 2 227,832 digits and takes up about 7 pages of newsprint. Obviouslythis program cannottest such a large number, since it's greater than the largest integer which can be represented by a Fortran intrinsictype.Ways oftesting such huge numbersfor primality are describedin D.E. Knuth, The Art of Computer Programming. Volume 2: Seminumerical Algorithms (Addison-Wesley, 1981) Knuth. The DO WHILE form of the DO construct would be very convenient to use here. Step 4 of the structure plan needs to be changed to
Try it out on the following: 4,058,879 (notprime), 193,707,721 (prime)and 2,147,483,647 (prime). 756,839
4. While R ≠ 0 and N
0) A = LOG( A ) ELSEWHERE A = 0 END WHERE
! log of all positive elements ! all non-positive elements set to zero
The ELSEWHERE clause is optional. The constructis analogous to IF-THEN-ELSE. The expression in parentheses after the keyword WHERE is a logical array expression, and may simply be alogical array.Itissometimes called a mask. There is a corresponding WHERE statement: WHERE (A /= 0) A = 1 / A ! replace non-zero elements by reciprocals
Array-valued functions A function may be array-valued. If it is an external function, it needs an interface block.
Array handling intrinsic functions There are a number ofintrinsicfunctions which relate specificallyto arrays. The completelistisin Appendix C. A sample is given here. ALL(X) returns the value .TRUE. only ifallthe elements ofthe logical array X aretrue. ANY(X) returnsthe value .TRUE. ifany element ofthe logicalarray X istrue. Otherwiseitreturns .FALSE. SUM(X) and PRODUCT(X) return the sum and product of the elements of the integer, real or complex array X respectively. In allthese cases X can be an array expression, e.g. INTEGER, DIMENSION(5,5) :: A REAL X(3), Y(3) ... IF (ANY(A > 0)) A = 1 ! if any element > 0 replace all by 1 IF (ALL(A == 0)) A = -1 ! if all elements = 0, replace all by -1
122
Dot = SUM( X * Y )
! scalar product of X and Y
Chapter 9 Summary •
•
•
•
•
•
•
• •
•
•
• •
•
•
•
Arrays are useful for representing and processing large amounts of data. An array is a collection of subscripted variables with the same name. Me mbers of an array are called elements. The number of elementsin an array isits size. The size may be zero. Upper and lower bounds of array subscriptsare specified withthe DIMENSION attributeinthe array type specification statement. An array subscript may not fall outside the bounds specified by DIMENSION. An array subscript may be any valid numeric expression (rounded if necessary). The number ofdimensions ofan arrayisitsrank. An array may have up to seven dimensions. A scalar has a rank of zero. The number of elements along a dimension of an array isthe extent ofthe dimension. The sequence of the extents of an array isits shape. An array may be passed as an actual argument to a subprogram. The dum my argument must have the same shape.Ifthe corresponding dum my argumentis an assumed-shape array it will take on the shape ofthe actual argument. A dynamic variable(which may be an array)isspecified withthe ALLOCATABLE attribute and may be allocated memory while a program is running. The memory may be deallocated later. A dum my argument may notbe allocatable. A rank-one array constant may be formed with an array constructor. An implied DO may be used in an array constructor. An array section is a subarray.
•
A section subscript given by a rank-one integer expression is a vector subscript.
•
A section is conformable with any array ofthe same shape.
•
•
•
•
•
•
Arrays with the same shape are conformable. A scalaris conformable with any array. Array expressions may be formed from conformable arrays. Array expressions may be assigned to conformable arrays. W hen an elementalintrinsic function takes an array argument,the function is applied to each element ofthe array. The WHERE construct controls operations on array elements according to a logical mask.
Exercises If Num is an integer array with the attribute DIMENSION( 100 ) writethelines of coding which will put the first 100 positive integers (1, 2,..., 100) into the elements Num(1), ..., Num(100); putthe first 50 positive even integers (2,...,100) into the elements Num(1),..., Num(50); Assign the integersin reverse order,i.e. assign 100 to Num(1), 99 to Num(2), etc. endalphalist Writesome statementsto put thefirst100 Fibonacci numbers(1,1, 2, 3, 5,break 8,...)into an array F(1),..., F(100). Salarylevels atan educationalinstitution are(inthousands of dollars):9, 10, 12, 15, 20,35 and 50. The number of employees at each level are, respectively, 3000, 2500, 1500, 1000, 400, 100, 25. Write a program which finds and writes:the average salary level; The number of employees above and below the average level; The average salary earned by an individualin the institution.
123
Write a program which reads 10 numbersinto an array, and printsthe mean, and the numberin the array furthestin absolute value from the mean. Develop a structure plan for the problem of writing allthe primes less than 1000 (1 and 2 are generally regarded as primes, prime number generationand will probably have to be dealt with separately). Writethe program. Hint: use an array to store the primes asthey are found. In an experiment N pairs of observations (Xi, Yi) are made. The best straight lineleast squares that may be drawn throughthese points(usingthe method of Least Squares) hasintercept A on the x-axis and slope B, where B = ( S1 − S2S3 / N ) / S4 − S22 / N A = S 3 / N − S2 B / N
(
)
and S1 =
∑ X iYi , S2 = ∑ X i , S3 = ∑ Yi , S4 = ∑ X i2
The correlation coefficient R is given by NS1 − S2S3 R= NS4 − S22 NS5 − S32 where S5 = sum Yi 2. (R = 1 implies a perfectlinearrelationship between Xi and Y. i Thisfact can be used to test your program.) All the sum m ations are over the range 1 to N. The observations are stored in a textfile.Itis not known how many observations there are. Write a program to read the data and compute A, B and R. Hint: you don'tneed arrays! Ifa set of points(X, i Yi) arejoined by straightlines,the value of Y correspondingto a value X which lies on a straightline between Xi and Xi+1 is given by
Y = Yi + ( X − X i )
(Yi +1 − Yi )
( X i +1 − X i )
This process is called linear interpolation. Suppose nolinear interpolationinterpolation more than 100 sets of data pairs are stored,in ascending order of X, i in a textfile.Write a program which will compute an interpolated value of Y given an arbitrary value of X keyed in at the keyboard. It is assumed that X isinthe range covered by the data. Notethatthe data mustbe sortedinto ascending order with respecttothe Xi values.Ifthis were not so,it would be necessary to sortthem first.
124
125
Chapter 10 Advanced Input and Output Chapter 10 Introduction 10.1. Rabbit Breeding the Fibonacci Way 10.2. The PRINT Statement 10.3. Formatting Features •
•
Edit descriptors
•
•
The character string edit descriptor
•
Repeat counts
•
Data edit descriptors Control edit descriptors Carriage control
10.4. Formatted READ 10.5. Formatted WRITE 10.6. Internal Files 10.7. External Files •
•
File positioning
•
Unformatted I/O
•
Sequentialfiles
•
Direct access files The INQUIRE statement
10.8. Non-advancing I/O 10.9. Miscellaneous •
•
List-directed I/O N A M ELIST
Chapter 10 Summary Chapter 10 Exercises
Chapter 10 Introduction So far we have concentrated on writing programs to solve various problems without paying too much attention to how the output looks. In this chapter we will see how to use FORMAT specifications to produce neater output. We will also look at datatransferinvolving files.
126
10.1. Rabbit Breeding the Fibonacci Way To make the exercise more interesting, we will write a program to model a rabbit population using the following assumptions: 1. We start with one new-born male/female pair. 2. A new-born pair produce a male/female pair aftertwo months. 3. Male/female pairs of age two months and older produce a male/female pair every month. If we representthe number of male/female pairs after n months by the variable Fn, some scratching around with a pencil and paper soon reveals that Fn takes the following values: Month n 1 2 3 4 5 6 7 8 Population Fn 1 1 2 3 5 8 13 ? The sequence {Fn} is calledthe Fibonacci sequence. We wantto write a program that computesthe total population for up to, say, 12 months. Note that this model does not allow for deaths; this possibilityis discussed in Chapter 15.It can be shown that each term inthe sequence isthe sum of the previous two, i.e. We therefore need to have three variables inthe program, Fn, Fn_1 and Fn_2, which need to be updated each month (assuming that we are not going to use an array). An interesting feature ofthe Fibonacci sequence isthat We will also computethisratio,to verifythatit has a limit (in fact,the limitisthe same whatever the firsttwo valuesinthe sequence are). The program below uses FORMAT statementsto controlthelayout ofthe output,to give you an idea of what can be done. The details arethen discussed. ! Rabbit breeding the Fibonacci way IMPLICIT NONE INTEGER Month REAL Fn, Fn_1, Fn_2 ! Format specifications 10 FORMAT( 'Month', T12, 'Population', T27, 'Ratio' / 5('-'), T12, 10('-'), T27, 5('-') / ) 20 FORMAT( I3, T12, F7.1, T27, F6.4 ) ! Now the executables Fn_1 = 1 Fn_2 = 1 PRINT 10
&
! heading
DO Month = 3, 12 Fn = Fn_1 + Fn_2 PRINT 20, Month, Fn, Fn / Fn_1 Fn_2 = Fn_1 Fn_1 = Fn END DO END Output: Month ----3 4 ...
Population ----------
Ratio -----
2.0 3.0
2.0000 1.5000
127
12
144.0
1.6180
Briefly, we have replaced PRINT* with PRINT n, where n isthe label (inthe range 1–99999) of a FORMAT statement, which specifies how the outputislaid out. The first FORMAT statement prints the headings.T12 tabulates to column 12, before printing any further output. The slash (/) starts a new record (line feed). The 5 (as in 5('-')) repeats what followsimmediately.Incidentally,the best wayto get your headingsrightisto putthem in after you have gotthe rest ofthe output looking as you wantit. The second FORMAT statement controls the output of the variables. I3 prints an integer over 3 columns. F7.1 prints a real over 7 columns with one decimal place. F6.4 prints a real over 6 columns with 4 decimal places. FORMAT statements, which are non-executable in the sense that they don't actually initiate any action, are usually grouped together for ease of reference, e.g. atthe beginning of a program.
10.2. The PRINT Statement The generalform ofthe PRINT statementis PRINT fmt [,list] where fmt may be one ofthe following:
•
• •
a statementlabelreferringto a FORMAT statement withtheformatspecificationsin parentheses, e.g. PRINT 10, X 10 FORMAT( 'The answer is: ', F6.2 ) an asterisk asin the list-directed I/O we have been using up to now, e.g. PRINT*, 'The answer is: ', X a character expression or constant which evaluatesto a format specification in parentheses,e.g. PRINT "( 'The answer is: ', F6.2 )", X
The quantitiesin list may be constants, expressions, variables, orimplied DO lists ofthe form do-list, variable = expr1, expr2 [,expr3]) where items in do-list may themselves be implied DO lists. READ can be used inthe same way as PRINT, exceptthatthe quantitiesin the list must be variables.
10.3. Formatting Features In this section we discuss the details of format control for input and output.
Edit descriptors Edit descriptors, such as F7.1 in the program above,specify exactly how a quantity should appear on output, or in preparation for input. More technically, they specify how a value represented internally bythe computershould be convertedinto a (readable)characterstring on an output device or file, or converted from a character string on an input device or file. There arethree categories of edit descriptors: data, character string, and control.
Data edit descriptors In the descriptions below, the symbols w, m, d and e all represent integer constants, while b represents a blank.
128
In all cases involving numeric output, if the specified field width is too narrow it is filled with asterisks. Integer values are converted by the I edit descriptor. The usualform is Iw, where w specifiesthe field width. The value isrightjustified inthis field, which must allow room for aleading minus sign. An alternative form for outputis Iw.m, which ensuresthata minimum of m digitsis printed, with leading zeros if necessary. E.g. I6.3 prints -99 as bb-099. Binary, octal and hexadecimal values are also converted by binary the Bw, Ow and Zw edit descriptors respectively. The minimum number of digits m may also be specified. For input, the leading letter(B, O or Z) and the delimitersmust be omitted. E.g. READ '(B4)', I will convertthe input string 1111 into the decimal value 15. Real values are converted by the F, E, EN or ES edit descriptors. The F (fixed point) descriptor hasthe form Fw.d, where w definesthetotalfield width (including a possible sign and the decimal point), and d defines the number of digits after the decimal point (rounded if necessary). E.g. –12.345 is printed under F8.2 as bb-12.35. On input,ifthe input string has a decimal point,the value of d isignored. E.g. b1.2345b is read underthe descriptor F8.2 as 1.2345. Iftheinputstring has no decimal point,the rightmost d digitsaretaken asthe decimal part. E.g. b12344 isread under F7.2 as -123.45. There are two other forms of input possible under the F descriptor. If the input is in standard scientific notation, or ifthe E is omitted from the standard form and the exponentis signed,the d specifieris againignored. E.g. 12.345E-2 (or 12.345-2b) isread under F9.1 as 0.12345. The E edit descriptor hastwo forms. For both ofthem,therulesforinputarethe same asthose for the F descriptor. On output, Ew.d produces a mantissamantissa (significand) of d digits with an absolute value lessthan 1 overa field of w. This mustinclude room for a possiblesign, the decimal point,and an exponent offourcharacters,consisting eitherof E followed by a sign andtwo digits,or of a sign and three digits. The form with E is not used ifthe magnitude of the exponentis greater than 99. E.g. 1.234 times 10^23 is written under E10.4 as b.1234E+24 or b.1234+024. The otherform of the E descriptoris Ew.dEe, where e determinesthe number of digitsto appearin the exponent field. This form is mandatory for exponents with a magnitude greaterthan 999. E.g. 1.234 times 101234 is written under E12.4E4 as b.1234E+1235. The EN (engineering) edit descriptor is the same as the E descriptor except that on output the exponentis divisible by three,the mantissais greaterthan or equalto 1 and lessthan 1000, and the scale factor (see below) is ignored. E.g. 0.00217 is written under EN9.3 as 2.170E-03 or 2.170-003. The ES (scientific) edit descriptoristhe same as the EN descriptor exceptthatthe mantissa isless than 10. Complex values may be controlled by pairs of F, E, EN, or ES edit descriptors. The real and imaginary parts may have different descriptors, which may be separated by character string and control edit descriptors. Logical valuesare controlled by the L editdescriptorinthe form Lw. On output T or F willappear in the right-most position of the field w. On input, optional blanks are optionally followed by a decimal point,followed by T or F (upper- or lowercase),optionally followed by additionalletters. This curious arrangementis simply to allow the strings .TRUE. or .FALSE. to be input. Character values are controlled by the A editdescriptorin one oftwo forms — A or Aw. Inthe form A,the width ofthe I/O fieldsis determined by the length ofthe character variable or expression in the I/O list. E.g.if NAME is declared
129
CHARACTER NAME*7 then 7 characters are output, and 7 characters areinput. Inthe second form (Aw),the w left-most characters are printed, on output.If necessary,the output field is blank-filled from the left. The rules for input under the second form are a little strange. Suppose len is the length of the variable being read.If w islessthan len,theleft-most w characters areread, padded with blanks on the right. E.g. under A5, the input string NAPOLEON is read into NAME (as declared above) as NAPOLbbb. However, and thisisthe strange bit,if w is greaterthan len,the right-most len characters are read. So under A8,for example,the string NAPOLEON isread into NAME as APOLEON. One would have expected the left-most charactersto be read. outindent Finally,there are the general Gw.d and Gw.dEe edit descriptors, which may be used for any oftheintrinsic datatypes.These descriptorsare usefulfor printing values whose magnitudes are not well-known in advance. W here possible values are output under the equivalent F descriptor; otherwise the equivalentform with E is used.
The character string edit descriptor A character constant (a string of characters enclosed in apostrophes or quotes) may be output by embedding itin a format specification, as we have already seen, e.g.
10
PRINT 10 FORMAT( 'Fortran 90 is the language for me' )
For completeness, we should mention the obsolescent H edit descriptor.It was named in honour of Hollerith, who invented punch cardsto process a censusinthe United States duringthelastcentury. An output character string (without delimiters) may be preceded by an nH descriptor, where the integer constant n isthe number of charactersinthe string,e.g. 10
FORMAT( 24HWe must count carefully! )
The drawback isthatyou mustcountthe number of charactersinthe string;itis very easy to make a mistake.
Control edit descriptors These edit descriptors enable you to position output precisely,start a new record, skip columns on input, etc. Embedded blanks in inputfields aretreated either as zeros, or as nulls (the default). The defaultis overridden by the BN (blanks null) and BZ (blanks zero) edit descriptors. The new mode holds for therest ofthe format specification, or untilexplicitly changed. E.g.theinputstring 1b31b3 isread under (BN, I3, BZ, I3) asthe two values 13 and 103. There arethree descriptors which controlthe leading signleading sign on output. A leading minusis printed by default. The SP (sign print) edit descriptor causes leading positive signs to be printed. The SS (sign suppress) descriptor suppresses leading plus signs while SP is in effect, and the S descriptorrestoresthe defaultoption. E.g.the value 99 writtenthreetimes under (SP, I3, SS, I3, S, I3) appears as +99b99b99. A sign descriptor holds for the rest of the format specification, unless changed by another sign descriptor. Scale factors oftheform kP may be applied toinput ofreal quantities underthe E, F, EN, ES and G edit descriptors. k is an integer constant specifying the scale factor. Any quantity without an exponent field is reduced by a factor 10 k. E.g. 1.0 isread under (2P, F3.0) as 0.01. Quantities with an exponent are not affected. A scale factor also affects output under E, F or G editing. Under F, a scale factor kP multiplies the output by a factor 10 k. Under E editing,and under G when the E optionistaken,the exponent ofthe outputisreduced by k, whilethe mantissa ismultiplied by 10 k.
130
A scale factor holds for the rest of the format specification, or until another scale factor is encountered. Tabulation ininput or outputfieldsis possiblein four ways. Tn causestabulation to position n of the currentI/O record. TRn (or nX)tabulates n positionstotheright ofthe current position, and TLn tabulates n positionstotheleftofthe currentposition (wherein allcasestabulation can never go to the left of position 1). On input,tabulation can be used to skip pastdata, orto re-read data. E.g.under (I1, 2X, I1) the input string 1234 isread as the two values 1 and 4. On output,tabulation can be used in the conventional way, or for (partial)replacement. E.g. under (I3, TL2, I3) the values 911 and 999 are output as 9999. A new record may be started at any point in a format specification by the slash (/) editdescriptor. It may have a repeat count, so /// is the same as 3/. It only needs to be separated by a com ma from a preceding descriptorifit has a repeatcount. Colon editing stopsformat controlifthere are no moreitems in an I/O list.In particular,itis useful in preventing unwanted character strings from being printed. E.g.the statements PRINT 10, (X(I), I = 1, N ) 10 FORMAT( 'X1:', I2 : ' X2:', I2 : ' X3:', I3 ) produce the output X1: 1 when N has the value 1. Withoutthe colons,the output would have been X1: 1 X2: Note thatthe colons do not need to be separated from neighbours by commas.
Repeat counts The data edit descriptors described above, as well as the new record (slash) descriptor, may all be preceded by a repeat count in the form of an integer constant. A repeatcount may be applied to a group of edit descriptors enclosed in parentheses, and may be nested, e.g. 3(2F6.2, 2(I2, 3I3)) If a format specification without any items in parentheses is completed before the I/O list is exhausted,a new record begins,andtheformatspecificationisrepeated.Furtherrecordsbegininthe same way untilthe I/O listis exhausted. E.g.thefollowing code printsan array of 100 elements, 20 elements perline: PRINT 10, (X(I), I = 1, 100) 10 FORMAT( 20I3 ) Similarly, on input,a new recordistaken from theinputfileeachtime the specification isrepeated. Any excess input data on the record is ignored. E.g.the code READ 10, I, J 10 FORMAT( I1 ) reads two values, 1 and 3,from the input records 12 34 A format specification without parentheses may therefore be thought of as a template of how the compiler seesthe entire I/O record.
131
However,if a format specification contains items in parentheses, when the format is exhausted a new record is taken and format control revertsto the left parenthesis corresponding to the second last right parenthesis—including a possible repeat count outside the parentheses. This is called reversion. E.g.in 10
FORMAT( F5.0, 2(F6.1, 3(F7.2) ), F8.3 )
new records start at 2(F6.1, ....
Carriage control Fortran'sformatted output statements were originally designed forline printers. For outputto such devices,the first character of each record is used for carriage control (an old-fashioned word from the days of mechanicaltypewriters). There are four options: b (blank) start a new line + remain on same line (overprint) 0 skip aline 1 advance tothe beginning of anew page A blankinthe firstcolumn effectively means no actionistaken,soitis good practiceto make sure a blankissentasthefirstcharacter,e.g.by starting allformatspecifications with T2 (begin writingin position 2). Otherwise,for example, printing an integer under FORMAT( I3 ) will cause a page throw every time the integer isinthe range 100–199! These conventions will not necessarily work on a dot-matrix printer connectedto a PC. However,a combination of OPEN and WRITE with the CHAR() intrinsic function can be used to send any special controlcharacterstothe printer. The following code sends a form feed character(new page): OPEN( 1, FILE = 'prn' ) WRITE( 1, 10 ) CHAR( 12 ) 10 FORMAT( A1 ) The controlcharacteris notrestrictedtothefirstpositioninthe outputrecord;itcan be anywhere.In this way you can send any ofyour printer's special printing codes.
10.4. Formatted READ The form ofthe READ statement we have used so faris READ fmt [,list] where fmt is alabel, asterisk or character string, asin PRINT. Thereisa more generalform, which allowsinputfrom files,and which canintercepterrorsand endof-file conditions gracefully,without causing the program to crash.Itis READ ([UNIT=]u,[FMT=]fmt [,IOSTAT=ios] [,ERR=errorlabel] [,END=endlabel]) [list] The only obligatory items are the format specifier fmt, as described above,and the unit specifier u. A unit is an I/O device, such as a printer,terminal, or disk drive, for example, which may be connected by the compiler to your program. Such a unit may have a unit number attached to it, which is usually in the range 1–99, forthe duration of a program. We have seen the only two situations where a unit number is not required. The PRINT normally expectsto outputto the terminal,and the firstform of READ above normally expects to read from theterminal.In such cases,the terminalis calledthe standard I/O unit.Your system may allow you to change the standard unit. The unit specifier u, when itis required, may be of three forms: an integer expression,an asterisk (which impliesthe standard input unit), or a character variable in the case of an internal file (see below).
132
The remaining specifiersare optional,and may be in any order.If IOSTAT is specified,ios must be an integer variable. After execution of READ ios has different (system-dependent) negative values depending on whetheran end-of-record or end-of-filecondition occurred,a positive valueifan error was detected, or the value of zero otherwise. The presence of IOSTAT prevents a crash if an exception occurs. Further detailsare given in Appendix B.
10.5. Formatted WRITE The generalform ofthe WRITE statement for formatted outputis WRITE ([UNIT=]u,[FMT=]fmt [,IOSTAT=ios] [,ERR=errorlabel]) [list] The specifiershave the same meanings asin the READ statement. The output device may be selected during program execution. You may be developing a large program which will eventually spew vast amounts of data out on the printer. To save time (and paper) while writingthe program, you may wantto be ableto specify whilethe program is running where the output should go. The following code should help (PRN and CO N are the names of the PC printer and terminalrespectively): CHARACTER OutputDevice*3 PRINT*, 'Where do you want the output ("prn" or "con")?' READ*, OutPutDevice OPEN( 1, FILE = OutputDevice ) WRITE( 1, * ) 'Output on designated device'
10.6. Internal Files It was mentioned above thatthe unitspecifierin READ or WRITE could be an internal file. Thisis basically a character variable (or array) which may be written to or read from. E.g. CHARACTER(50) CAPTION ... WRITE( CAPTION, 10 ) YEAR 10 FORMAT( 'Sales figures for the financial year: ', I4 ) CAPTION couldthen be used as a caption in a graphical display. Internalfiles provide a general means of converting numeric datato strings, and vice versa. READ may be used to reversethe above process.In the code below,the string "1984" is convertedto an integer with the value 1984. CHARACTER (30) STRING STRING = "1984" READ( STRING, 10 ) NYEAR 10 FORMAT( I4 )
10.7. External Files Output from a program may be sent to an external file (e.g.residing permanently on a disk), and input may also be fetched by a program from such a file.This powerful facility provides a means of keeping records which may need to be updated, examined and analysed. Thereis a certain amount of jargon that needsto be overcome before we can proceed.In Fortran, a fileis said to exist if a program is able to access it. Existence istherefore a relative term, defined from the pointof view ofthe program attempting access. A file which existsfor a program may or may not be empty, and it may or may not be connected to that program. A file is connected by association with a unit number known tothe program. Thisconnectionis usually made by an OPEN statement, butcertain files may be automatically pre-connected.
133
A file may be thought of as a stream of data, arranged into records. The records are all either formatted, or unformatted. Files may be accessed sequentially, or directly; normally a particularfile isrestrictedto one mode of access.If accessis direct,allrecords must have the same length;thisis not necessary under sequential access. Inthe rest ofthis chapter we outlinethe main file handlingfacilities of Fortran 90. More substantial examples follow in later chapters.
File positioning A file has a current position which may be
•
•
within a record;
•
ahead ofthe firstrecord (the initial point);
•
between records; afterthe lastrecord (the terminal point).
Sequential files A sequential file may be thought of as a continuous tape, where records are located sequentially along the tape.Ifthe fileis formatted,the records may be of varying length,i.e.the record length does not need to be specified. A sequentialfile may be read onlyfrom the beginning. This makesthe accesstime slowerthan for a direct access file,since to find something nearthe end of a sequentialfile, you have to read every record from the beginning. You also cannot replace or remove a record directly, as you can with directaccessfiles. However,sequentialfilesare helpfulin situations where you might needto access thefile with a word processor—inthiscontextthefile would be atext(or ASCII)file.We have seen sequentialfiles in action in reading data from disk files. The following example shows how to update a sequential file.Itreads a line of textfrom the file, and asks you if you want to delete the line.If you don't want to deletethe line,itis written to a temporary (SCRATCH) file.The originalfileisthen deleted, a new emptyfile ofthe same name is created,and finallythe contents ofthetemporaryfileiscopied back.Itsounds cumbersome, because itiscumbersome. Manipulation of sequentialfiles usuallyis. Trythe program out on a textfile with a few names in it, which you can set up with yourtext editor. CHARACTER(80) Name, FileName, Ans WRITE( *, '(A)', ADVANCE = 'NO' ) "Name of file to be updated: " READ*, FileName OPEN( 1, FILE = FileName ) OPEN( 2, STATUS = 'SCRATCH' ) IO = 0 DO WHILE (IO == 0) READ( 1, *, IOSTAT = IO ) Name IF (IO == 0) THEN PRINT*, Name WRITE( *, '(A)', ADVANCE = 'NO' ) "Delete (Y/N)? " READ*, Ans ! could be upper or lowercase IF (Ans /= 'Y' .AND. Ans /= 'y') WRITE( 2, * ) Name END IF END DO REWIND( 2 ) CLOSE( 1, STATUS = 'DELETE' ) OPEN( 1, FILE = FileName )
! back to the beginning of SCRATCH ! delete original ! recreate original
IO = 0 DO WHILE (IO == 0) READ( 2, *, IOSTAT = IO ) Name
134
IF (IO == 0) WRITE( 1, * ) Name END DO CLOSE( 1 ) CLOSE( 2 ) END
! keep ! delete
Notethatthetwo DO WHILE loops make use ofthe IOSTAT specifierto avoid an attempted READ pastthe end ofthe file. The OPEN statement has the form OPEN( [UNIT = ]u, speclist ) where u isthe file unit number,and speclist is a list of specifiers, many of which are optional,and may be in any order. The unit number must appear first, unless itis specified with UNIT=. The specifiers are character expressions or constants.If character expressions are used, trailing blanks are ignored. Except forthe FILE specifier,lowercase letters are converted to uppercase. You also need to know thatthe OPEN statement can be executed on a unit number whichis already connected to a file. This is to enable the properties of a connection to be changed, and is only allowed with certain specifiers, for example, the BLANK specifier which sets the default for the interpretation of blanks to nulls or zeros. Some of the more com mon specifiers are described below; you should consult Appendix B for all the gory details. The FILE specifieris a character expression which givesthe name of the file.Ifthis specifieris omitted (and the unitis not already connected) the STATUS specifier must appear with the value SCRATCH. If SCRATCH isspecified forthe STATUS specifier(as above on unit 2),atemporary fileis created. It ceasesto exist when the unitis closed, or when the program terminates.If NEW is specified,the file mustnotalready exist.IfOLD isspecifiedit mustalready exist.If REPLACE isspecified,thefile is created ifit does not exist;ifit does exist,itis deleted,and a new file is created withthe same name. The simple form of the OPEN statement used in the program above connects a file for sequential access(the default mode of access), withformattedrecords(the defaultforsequentialaccess). These properties may be changed by the ACCESS and FORM specifiers, as we shallsee below. New data may be written at the end of a sequential file by setting the POSITION specifier to APPEND. Errors (e.g. attempting to open a non-existent file with status OLD) may be intercepted with the IOSTAT and ERR specifiers. This avoids a crash; you can program a more gracefulresponse. A sequentialfile may be repositioned to itsinitial point with the statement REWIND u The statement BACKSPACE u positions a sequentialfile beforethe currentrecord ifitis positioned within a record, or beforethe preceding recordifitis positioned between records. This statementis costlyin computer overheads and should be avoided. The end of a sequentialfileis marked by a specialrecord called the endfile record. Most computer systems will automatically writethis record at the end of a sequentialfile. However,if you are in doubt, you can write an endfile record explicitly with ENDFILE u A fileis disconnected with a CLOSE statement.Itcan take the form CLOSE( [UNIT = ]u [, STATUS = st] )
135
wherethe STATUS specifier may be specified as KEEP or DELETE. A file may therefore be erased on disconnection, as in the example above. The default value is KEEP, unless the file has status SCRATCH, in which case the default (and only) value is DELETE. All connected units are automatically closed when a program terminates normally(even ifthere are no CLOSE statements), and a CLOSE on an unconnected unitdoes not cause an error. However,you should make a point of closing all yourfiles (and no others!),since itshows that you know whatyou are doing.
Unformatted I/O A file'srecords may be unformatted. The advantage of thisisthatthey take up much less storage than formattedrecords. E.g.thelargestinteger available underthe FTN90 compiler(2,147,483,647) takes up only 4 bytes on an unformatted record (since it can be represented with 32 bits), but 10 bytes on a formatted record (the number ofcharacters required to representit). A sequential file is formatted by default, so the FORM specifier must be used if it is to be unformatted, asinthe next example, which writes an integer array and reads it back. INTEGER, DIMENSION(10) :: A = (/ (I, I = 1,10) /) OPEN( 1, FILE = 'TEST', FORM = 'UNFORMATTED' ) WRITE (1) A REWIND (1) A = 0 ! just to be sure ! READ (1) A PRINT*, A CLOSE (1) END Note thatto read the fileit must be rewound,since itissequential(by default). Each READ and WRITE transfers exactly one record. The file created in this exampletherefore has one record, containing an array of 10 integers. W hen outputisto a sequentialfile a record of sufficientlength is created. On input,the number of items in the inputlist must not exceed the number of valuesinthe record.
Direct access files Inthe case of direct or random accessfiles,a particularrecord may be read and/orrewritten, unlike the case with sequential access files, where records may not in general be replaced. Records may also be added atthe end of a direct access file withoutrewriting the whole file. Directaccess files are unformatted by default,and alltheirrecords must bethe same length.Thisrecordlength must be specified with the RECL specifierinthe OPEN statement.Record length is generallythe number of bytes occupied by the item written to the file, but may be system dependent. The INQUIRE statement may be used to find the record length (see below). The following example reads a list of names from the keyboard, writesthem to a direct access file,readsthem back, and finally replaces the third record. CHARACTER (20) NAME INTEGER I INQUIRE (IOLENGTH = LEN) NAME OPEN( 1, FILE = 'LIST', STATUS = 'REPLACE', ACCESS = 'DIRECT', & RECL = LEN ) DO I = 1, 6 READ*, NAME WRITE (1, REC = I) NAME END DO DO I = 1, 6 READ( 1, REC = I ) NAME PRINT*, NAME END DO
136
! write to the file
! read them back
WRITE (1, REC = 3) 'JOKER' DO I = 1, 6 READ( 1, REC = I ) NAME PRINT*, NAME END DO
! change the third record ! read them back again
CLOSE (1) END Note that a direct access file behaves like an array.In fact,if memory isin short supply, data can easily be handled with a direct access file, rather than in an array. If the file is stored on a RA M (virtual) disk there is practically no difference in accesstime. The record number is given by the REC specifier in the READ and WRITE statements, which otherwise have the same forms as for sequentialfiles.
The INQUIRE statement This statement may be used to ascertain the status and attributes of connected files, and unit numbers, and the record length of an output list. It has three forms:INQUIRE by output list (as above), INQUIRE by unit,and INQUIRE by file. Inquiry by outputlist hasthe form INQUIRE (IOLENGTH = length) output list This form may be used to establish the length ofthe unformatted record of an outputlist. An example of inquiry by unit number is INQUIRE ([UNIT = ]u, EXIST = allowed) The logical variable allowed willbe assigned the value .TRUE. if unitnumber u is an allowed unit number for your system, and .FALSE. otherwise. The existence of a file may be established similarly: INQUIRE (FILE = filename, EXIST = allowed) You can use the EXIST specifierto avoid accidentally overwriting or deleting an existing file. The number of the record mostrecently read or written isreturned with the NEXTREC specifier. Further detailsare in Appendix B.
10.8. Non-advancing I/O Normally READ and WRITE transfer complete records. This can be a nuisance. A new feature of Fortran 90 is non-advancing I/O, whereby a fileisleft positioned within the currentrecord. We have seen the use of non-advancing WRITE in giving screen prompts: WRITE (*, '(A)', ADVANCE = 'NO') 'Enter a number: ' READ*, Number Non-advancing READ can also be useful,for example,inreading individual charactersfrom a text file. The following program countsthe number of charactersin atextfile: CHARACTER (1) ch INTEGER IO, Num OPEN( 1, FILE = 'TEXT' ) IO = 0 Num = 0
137
DO WHILE (IO /= -1) ! EOF READ (1, '(A1)', IOSTAT = IO, ADVANCE = 'NO') ch IF (IO == 0) Num = Num + 1 ! genuine character read END DO PRINT*, Num CLOSE (1) END Under FTN90 the IOSTAT specifierreturns-1 whenthe end-of-fileisencountered,as opposedto-2 for end-of-record. Non-advancing I/O is not available with list-directed I/O.
10.9. Miscellaneous For completeness,two furthertopics need to be mentioned here:list-directed I/O, and NAMELIST.
List-directed I/O As we have seen,thistakes the form READ*, list PRINT* [, list] Data in the inputlist may be separated by com mas, slashes or atleast one blank (separators). The real and imaginary parts of complex constants must be enclosed in parentheses. Characterconstants enclosed in delimiters('apostrophes'or"quotes") may be spread over morethan one record. Delimiters may be omittedifthe characterconstant does not contain a blank, com ma, or slash;ifitis contained within one record;ifthe firstcharacteris not a delimiter;and ifthe leading characters are not numeric followed by an asterisk. The reason forthe last proviso isthat a data value which isto be repeated n times may be given a repeat count n*. E.g. 6*0 means the value zero isto be read six times. If there is no data value between successive separators, the corresponding input item is left undefined (under the FTN90 compiler—although the standard requires that itis left unchanged). E.g.the code CHARACTER (20) Name A = 3; B = 3; C = 3; D = 3; READ*, Name, A, B, C, D PRINT '(A, 4F6.2)', Name, A, B, C, D underthe FTN90 compiler, withinput "fortran 90", 2*, 2*7 gives the output fortran 90
2.20
2.20
7.00
7.00
(2.2 is a garbage undefined value).
NAMELIST Thisis a curiousfacility which can be usedto name a group ofitems forI/O purposes.Itallows you to omit input data for some items in the group. The group of items is named in a NAMELIST statement (MYOUT in the example below). The group name may either be specified with the NML specifier in READ or WRITE, or it may replace the format specifier. An input record must be prefaced by /&/followed by the group name. Data values may be omitted (in which casethe record
138
must end with a slash), and do not have to be in the order specified in the NAMELIST statement. Items not specified inthe inputrecord areleft unchanged. E.g. INTEGER, DIMENSION(4) :: A = 7 NAMELIST/MYOUT/A, X, Y X = 1 Y = 1 READ( *, MYOUT ) WRITE( *, NML = MYOUT ) Input: &MYOUT A(1:2) = 2*1 Y = 3 Output: &MYOUT A = 1 1 7 7, X =
1.0000000, Y =
3.0000000
The array section A(3:4) and the variable X are left unchanged.
Chapter 10 Summary •
•
• •
•
•
•
A record can be thought of as aline ofinput/output. Format specifies the layout of arecord. Format may be specified by alabelled FORMAT statement,by an asterisk (list-directedI/O), or by a characterstring. The PRINT statement generally only handles outputtothe screen. Implied DO lists may appearin I/O lists. The WRITE statement can handle outputto a file or printer.
•
The READ statement handles input from a file orthe keyboard.
•
Formatis controlled by edit descriptors.
•
•
• •
•
•
/O may be list-directed,formatted or unformatted. The OPEN statement connects a fileto a unit number,to enable transfer of data. The INQUIRE statement obtains information about files, unit numbers and record lengths of outputlists. Various specifiers,such as IOSTAT, END, and ERR may be used in I/O statementsto intercept and handle end-of-file conditions and possible errors. Data may be transferred directlyto or from a character array,inthe form of an internalfile. Disk files are examples of externalfiles.
•
Files consist of records, which may be formatted or unformatted.
•
Under sequential access,records are formatted by default,and theirlength may vary.
• • •
•
•
Files are accessed sequentially (the default)or directly (random access). New records may be appended to a sequentialfile (added on atthe end), but existing records may not be rewritten. Under direct access,records are unformatted by default,must all be the same length,and this record length must be specified in the OPEN statement. Under direct access, existing records may be rewritten, and new records may be appended. Direct accessis generally more efficientthan sequential access. If non-advancing I/O is specified,incomplete records may be transferred by READ or WRITE.
Chapter 10 Exercises
139
10.1 Give the output of the following two program segments (indicate blanks and new lines carefully): (a) 10
FORMAT (1X, 'M=', I3, 'N=', I4, 3X, 'X=', F6.1 / T3, E11.4) M = 117 N = -27 X = -0.1235E2 Y = 1234.567 PRINT 10, M, N, X, Y
(b) 10 20
FORMAT (I3, 1X, F6.2, F5.3, I2) FORMAT (T2, I2, F8.2 / T3. F3.1, I4 ) READ 10, N, X, Y, J PRINT 20, J, X, Y, N Data: /0146729.123.61035/ 10.2 Show how each of the following values will be printed with the edit descriptors shown (assume that carriage controlhas been taken care of):
(a)-738 (I4) (b) +738 (I3) (c) 38.136 (F7.2) (d) -100.64 (F6.1) (e) 9876.545 (E10.4) (f)-0.000044009 (E9.2) 10.3 Write aprogram which will count allthe non-blank charactersin atext file of any size. 10.4 a) Writea program which sets up a directaccessfile where each unformatted record contains a one-dimensionalinteger array of size 10,say. Write some test datatothe file,and read it back to make sure it gotthere. (b) Write a separate program which will add one extra record of the same length to the end of the file created in part(a). 10.5 Writea program which willread a positiveinteger(ofany size),finditsbinary code,and print the binary code on one line with no blanks between the digits. Hint: afterfinding each binary digit, store itin a different element of an allocatable array.
140
Chapter 11 Handling Characters Chapter 11 Introduction 11.1. Characters 11.2. Bar Charts and Frequency Distributions 11.3. Sorting Words 11.4. Graphs Without Graphics 11.5. Word Count and Extraction 11.6. General Information •
Character substrings
• •
Assumed characterlength
•
•
Embedded format
•
Concatenation Character array constructors Character handling intrinsic functions
Chapter 11 Summary Chapter 11 Exercises
Chapter 11 Introduction We have seen some simple examples of the use of the intrinsic character type. Armed with the further weapons of arrays and more advanced I/O facilities we can now tackle more interesting problems involving characters, or strings as they are often called.
141
11.1. Characters To recap, a character constant is a string of characters enclosed in delimiters, which are either 'apostrophes' or "quotes". The delimiters are not part ofthe string. Character variables may be declared inthe following ways: CHARACTER ALPHA CHARACTER (15) Name CHARACTER Word*5
! length of 1 ! length of 15 ! length of 5
Assignmentisdone as follows: Name = "Bonaparte, N"
11.2. Bar Charts and Frequency Distributions The first example utilizes an array and the A edit descriptor for printing characters. Suppose we want to analyse the results of a test written by a class of students. We would like to know how many students obtained percentage marks in the range 0-9, 10-19, ..., 90-99. Each of these ranges is called a decile, numbered from zero for convenience. We also need to caterforthe bright sparks who get 100 (the eleventh "decile"). Suppose the numbers of students who get marks inthese ranges are as follows: 1 0 12 9 31 26 49 26 24 6 1 i.e.12 obtained marksinthe range 2029. W e need an array F(0:10),say, with 11 elements, where each element stores the number of students with marks in that particularrange, e.g. F(2) should have the value 12. The following program prints a bar chart ofthe frequency distribution F, where each asterisk represents one studentinthatrange: INTEGER, DIMENSION(0:10) :: F = (/ 1, 0, 12, 9, 31, 26, 49, 26, & 24, 6, 1 /) 10 20
FORMAT( I3, ' - ', I3, ' (', I3, '):', 60A1 ) FORMAT( '100', 6X, ' (', I3, '):', 60A1 )
DO I = 0, 10 IF (I < 10) THEN PRINT 10, 10 * I, 10 * I + 9, F(I), ('*', J = 1, F(I)) ELSE PRINT 20, F(I), ('*', J = 1, F(I)) END IF END DO END Output: 0 10 20 30 40 50 60 70 80 90 100
142
-
9 19 29 39 49 59 69 79 89 99
( ( ( ( ( ( ( ( ( ( (
1):* 0): 12):************ 9):********* 31):******************************* 26):************************** 49):************************************************* 26):************************** 24):************************ 6):****** 1):*
Notethe absence of asterisks forthe 10-19 decile. Thisis because F(1) hasthe value zero,so that the implied DO inthe PRINT statement has a zero trip count when I has the value 1. Of course,in arealsituation,thefrequencies willnot be presentedto you neatly on a plate. You are morelikelyto have a listofthe actual marks. You should adaptthe program to read a sample set of marks,inthe range 0-100, and to convertthem into frequencies. The basic mechanism is READ( ... ) MARK K = INT( MARK / 10 ) F(K) = F(K) + 1
! K is the decile ! another mark in the Kth decile
11.3. Sorting Words Characters may be comparedin IF statements;thisisthe basis of alphabeticsorting. Each computer system has a collating sequence which specifiestheintrinsic ordering ofthe available characterset. The Fortran 90 standard requires only that
•
•
•
A < B < C ... < Y < Z 0 < 1 < 2 ... < 8 < 9 blank < A and Z < 0, or blank < 0 and 9 < A
Iflowercase letters are available,there arethe further requirementsthat
•
•
a < b < c ... < y < z blank < a and z < 0, or blank < 0 and 9 < a
Note thatthe standard does notinsist on how the lowercase characters are to be ordered relative to uppercase. There are two intrinsic functions thatrelate a characterto its position in the collating sequence (or more simply,its code). ICHAR( 'A' ) returns an integercode foritscharacterargument,e.g. 65, say,inthis case. CHAR( 90 ) returns the character coded by itsinteger argument, e.g. Z, say. Furthermore,the standard requiresthat access be provided to the ASCII(American Standard Code for Information Interchange) collating sequence,in which Z < a (see Appendix D). There are two further intrinsic functions, which specifically relate a character to its ASCII code: IACHAR and ACHAR. However, some computers make use of the EBCDIC collating sequence (Extended Binary Coded Decimal Interchange Code— pronounced "ebsadik"). In EBCDIC, unfortunately, the lowercase characters come before the uppercase ones,so z < A. This hasimplications for word sorting, since we normally requirethat bOnApArTe < NaPoLeOn whateverthe case ofthe characters. One way outisalwaysto use ASCII code, butthis may be inefficient on some computer systems. A more general solution isto write a subroutine to convertlowercase alphabeticlettersto uppercase, based on ICHAR and CHAR, which do not rely on the ASCII code. The subroutine ToUpper in the next program does this.It uses ICHAR( 'A') and ICHAR( 'a' ) to determine the "distance" betweenthe upper-andlowercaseletters(assuming allthe letters of one caseto be contiguous,i.e.to have consecutive codes).Itthen addsthis distanceto allthelowercaselettersinthe word —carefully avoiding uppercase letters and all non-letters. To test it,the program reads two words from the keyboard(e.g.NAPOLEON and bonaparte),printsthem in "ascending" orderasthey are,converts them both to uppercase, and printsthem in order again. IMPLICIT NONE CHARACTER (10) Word1, Word2
143
READ*, Word1 READ*, Word2 IF (Word1 < Word2) THEN PRINT*, Word1, Word2 ELSE PRINT*, Word2, Word1 END IF CALL ToUpper( Word1 ) CALL ToUpper( Word2 ) IF (Word1 < Word2) THEN PRINT*, Word1, Word2 ELSE PRINT*, Word2, Word1 END IF CONTAINS SUBROUTINE ToUpper( String ) CHARACTER (LEN = *) String INTEGER I, Ismall, IBIG Ismall = ICHAR( 'a' ) IBIG = ICHAR( 'A' ) DO I = 1, LEN( String ) IF (String(I:I) >= 'a' .AND. String(I:I) X(1) ! symbolic aliases ... Pred => X(2) ! ... reduce likelihood of errors p => Params(1) % Val q => Params(2) % Val r => Params(3) % Val s => Params(4) % Val F(1) = p * Prey - q * Prey * Pred F(2) = r * Prey * Pred - s * Pred END SUBROUTINE DEqs DEqs evaluates and returnsthe right-hand side ofthe ith differential equation in the ith element of the array F. To allow the userto use more meaningfulsymbolic namesforparametersand variables, aliases are set up between the symbolic names and the system variables declared in DrGlobal.
239
This is why DEqs must access the module DrGlobal, and why the current values of the model variables mustbe held inthe array X. The use of aliases makes it much easierto code large models. The module DrUtils mustaccess DrGlobal, and looks as follows: MODULE DrUtils ! Driver utility subroutines USE DrGlobal IMPLICIT NONE INTERFACE SUBROUTINE DEqs( F ) REAL F(:) END SUBROUTINE DEqs END INTERFACE
! defines model DEs
CONTAINS SUBROUTINE Headings ! generates output headings INTEGER I PRINT "(3A11)", "Time", (Vars(I) % Name, I = 1, NumVars) PRINT* PRINT "(3F11.2)", T, X END SUBROUTINE Headings SUBROUTINE Initialize ! All this info could be read from a disk file NumVars = 2 NumParams = 4 ALLOCATE( Vars(NumVars), Params(NumParams), X(NumVars) ) Vars(1) % Name = "Prey" Vars(1) % InVal = 105 Vars(2) % Name = "Pred" Vars(2) % InVal = 8 Params(1) % Val = 0.4 Params(2) % Val = 0.04 Params(3) % Val = 0.02 Params(4) % Val = 2.0 Vars % Val = 0 ! set current values to zero for safety dt = 1 T = 0 RunTime = 10 END SUBROUTINE Initialize SUBROUTINE Run CALL Headings DO Itime = 1, RunTime T = T + dt CALL Runge PRINT "(3F11.2)", T, X END DO Vars % Val = X END SUBROUTINE Run
! run the model
! current values
SUBROUTINE Runge ! 4th order Runge-Kutta REAL :: F(NumVars) REAL, DIMENSION( NumVars ) :: A, B, C, D, V ! working space REAL h A = 0; B = 0; C = 0; D = 0 ! initialize V = X ! initialize for Runge-Kutta
240
CALL DEqs( F ) A = dt * F X = V + A / 2 ! V has original X, update X CALL DEqs( F ) B = dt * F X = V + B / 2 CALL DEqs( F ) C = dt * F X = V + C CALL DEqs( F ) D = dt * F X = V + (A + 2 * B + 2 * C + D) / 6 ! finally update X for return END SUBROUTINE Runge SUBROUTINE TidyUp ! close files, throw away dynamic storage, etc. DEALLOCATE( Vars, Params, X ) END SUBROUTINE END MODULE DrUtils It has an (optional)interface block forthe external subroutine DEqs. Headings generates headings forthe output from a run,including the initial values forthatrun. Initialize allocates dynamic storage,sets up model variable and parameter names and values, and also initializes other global variables. Note that allthisinformation could be read from a disk file(which itself could be setup by another subroutine). The subroutine Run actually runs the model. It generates headings, integrates the differential equations RunTime times by calling Runge, and finallysetsthe final values ofthe variablesfrom X. Note that Vars % Val is a valid array section:the array X can therefore be assigned to it. Runge integratesthe differential equations over one step-length dt, calling DEqs to supply their right-hand sides. TidyUp deallocates dynamic storage, and would be the place to close files, etc. Finally,the package is driven by the main program Driver: PROGRAM Driver ! Runs differential equations models ! Model DE must be defined in external subroutine DEqs USE DrGlobal ! global declarations USE DrUtils ! Driver subroutines IMPLICIT NONE CALL Initialize Opt = "" PRINT*, "Driver Sample Model" PRINT* DO WHILE (Opt /= "Q" .AND. Opt /= "q") PRINT*, "C: Carry on" PRINT*, "I: Initial run" PRINT*, "Q: Quit" PRINT* READ*, Opt PRINT* SELECT CASE (Opt) CASE ("C", "c") X = Vars % Val CALL Run CASE ("I", "i") X = Vars % InVal T = 0
241
CALL Run END SELECT END DO CALL TidyUp END PROGRAM Driver Driver uses both modules,and allows two basic options atthe moment:to run the modelfrom its initial values (I), orto run from the currentvalues (C). Ifaninitialrunisselected, X isassignedinitial values,and T issetto zero,before Run iscalled.Ifa carry on is selected, X is assigned current values, and T isleft unchanged. A sample run using the datain this example is as follows: Driver Sample Model C: Carry on I: Initial run Q: Quit Enter your option: I Time Prey 0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
105.00 110.88 108.32 98.83 91.12 90.30 95.81 104.30 110.45 108.61 99.58
Pred 8.00 9.47 11.65 12.57 11.26 9.24 7.98 7.99 9.34 11.48 12.52
... Depending on your enthusiasm, you could extend thisskeleton a great deal. You could even write a procedure for setting up a new model, which asks the user for symbolic names of variables and parameters,and which generates the aliasing code for subsequentinclusion into DEqs. Thisis very usefulforlarge models.
16.7. Partial Differential Equations: a Tridiagonal System The numerical solution of partial differential equations (PDEs) is a vast subject. Space only permits one example, which serves two important purposes. It demonstrates a powerful method of solving a class of PDEs called parabolic. It also illustrates a method of solving tridiagonal systems of linear equations.
Heat conduction The conduction of heat along athin uniform rod may be modelled by the partial differential equation
∂U ∂ 2U = 2 ∂t ∂x
(16.17)
where U(x, t) isthe temperature distribution a distance x from one end of the rod at time t. It is assumed that no heatislostfrom the rod along itslength.
242
Halfthe battlein solving PDEs is mastering the notation. We set up a rectangular grid, with steplengths of h and k inthe x and t directionsrespectively. A general point on the grid has co-ordinates
xi = ih, y j = jk
. A concise notation for U(x,t) at
xi , y j
isthen simply
Ui , j
.
U
Now i , j is of course the exact solution of the PDE. Exact solutions can only be found in a few special cases; we want a general method forfinding approximate solutions. This is done by using truncated Taylor series to replace the PDE by a finite difference scheme. We define solution ofthefinite difference scheme atthe grid point solutions for
ui , j
xi , y j
ui , j
as the
.We now attemptto find numerical
,which willtherefore be our approximation to the exact solution
Ui , j
.
The left-hand side of Equation 16.17 is usually approximated by a forward difference:
∂U ui , j +1 − ui , j = k ∂t
One way of approximating the right-hand side of Equation 16.17 is as follows:
∂ 2U ui +1, j − 2ui , j + ui −1 j = ∂x 2 h2
(16.18)
Thisleads to a scheme, which although easy to compute,isonly conditionally stable. Ifhowever we replacetheright-hand side ofthe scheme in Equation 16.18 by the mean ofthe finite difference approximation onthe jth and (j+1)thtime rows,we getthefollowing scheme for Equation 16.17:
− rui −1 j +1 + (2 + 2r )uij +1 − rui +1 j +1 = rui −1 j + ( 2 − 2r )uij + rui +1 j
(16.19)
where r = k / h . This is known as the Crank-Nicolson implicit method, since it involves the solution of a system of simultaneous equations, as we shallsee. 2
To illustrate the method numerically,let's suppose thatthe rod has a length of 1 unit,and thatits ends arein contact with blocks ofice,i.e.the boundary conditions are U(0, t) = U(1, t) = 0. Suppose also thatthe initialtemperature is given by the initial condition
2 x, 0 ≤ x ≤ 1 / 2 U ( x ,0) = 2(1 − x ), 1 / 2 ≤ x ≤ 1
This situation could come about by heating the centre ofthe rod for a long time, withthe ends kept incontact withtheice,removingthe heatsource attime t = 0. This particularproblem hassym metry aboutthe line x = 1/2; we exploitthisfactin finding the solution. If we take h = 0.1 and k = 0.01, we will have r = 1, and Equation 16.19 becomes
− ui −1, j +1 + 4ui , j +1 − ui +1, j +1 = ui −1, j + ui +1, j
Putting j = 0 then generatesthefollowing setof equationsforthe unknowns u i ,1 up tothe midpoint ofthe rod,represented by i = 5,i.e. x = ih = 0.5. Exact and approximate solutions coincide on the boundaries and attime t = 0.The subscript j = 1 has been dropped for clarity:
0 + 4u1 − u2 = 0 + 0.4 − u1 + 4u2 − u3 = 0.2 + 0.6 − u2 + 4u3 − u4 = 0.4 + 0.8 . − u3 + 4u4 − u5 = 0.6 + 10 − u4 + 4u5 − u6 = 0.8 + 0.8
243
Sym metry then allows us to replace u6 in the last equation by u matrix form as 4 −1 0 0 0
−1 4 −1
0 −1 4 −1 0
0 0
0 0 −1 4 −2
4
. This system can be written in
0 u 1 0.4 0 u 2 0.8 . 0 u 3 = 12 . −1 u 4 16 . 4 u 5 16 (16.20)
The matrix(A) on theleftof Equation 16.20is known as a tridiagonal matrix. Such a matrix can be represented by three one-dimensional arrays:one for each diagonal. The system can then be solved very efficiently by Gauss elimination. This will not be explained here, but simply presented in a working program. Care needs to be taken with the matrix representation. The following form is often chosen: b1 a 2 A=
c1 b2 a3
c2 b3
c3 an −1 bn −1 an
c n −1 bn
Noting how the subscriptsrun, we will have to dimension as follows: A(2:N), B(N), C(1:N-1). The following program implementsthe Crank-Nicolson methodto solvethis particularproblem over 10 time steps of k = 0.01. The step-length h isspecified by N: h = 1/(2N) because of thesym metry. r istherefore not restricted to the value 1, although ittakes this value inthe program. PROGRAM CrankNicolson IMPLICIT NONE INTEGER, PARAMETER :: N = 5 REAL A(2:N), B(N), C(1:N-1), U(0:N+1), G(N), UX(N) INTEGER I, J REAL H, K, R, T K = 0.01 H = 1.0 / (2 * N) R = K / H ** 2 ! set up A, B, C A = -R A(N) = - 2 * R B = 2 + 2 * R C = -R DO I = 0, N U(I) = 2 * I * H END DO U(N+1) = U(N-1)
! symmetry assumed
! symmetry
! initial conditions ! symmetry
T = 0 PRINT "(A6, 10F8.4)", "X =", (I * H, I = 1, N) PRINT*, " T" PRINT "(F6.2, 10F8.4)", T, U(1:N) DO J = 1, 10 T = T + 0.01 G = R * (U(0:N-1) + U(2:N+1)) + (2 - 2 * R) * U(1:N) ! general R CALL TriDiag( A, B, C, UX, G )
244
PRINT "(F6.2, 10F8.4)", T, UX U(1:N) = UX U(N+1) = U(N-1) ! symmetry END DO CONTAINS SUBROUTINE TriDiag( A, B, C, X, G ) ! Solves the tridiagonal system Ax = g by Gauss elimination IMPLICIT NONE REAL B(:) ! main diagonal REAL A(2:) ! lower diagonal REAL C(:) ! upper diagonal REAL, INTENT(OUT) :: X(:) ! unknown REAL G(:) ! RHS REAL W( SIZE(B) ) ! working space REAL T INTEGER I, J, N N = SIZE(B) W = B DO I = 2, N T = A(I) / W(I-1) W(I) = W(I) - C(I-1) * T G(I) = G(I) - G(I-1) * T END DO ! back substitution X(N) = G(N) / W(N) DO I = 1, N-1 J = N-I X(J) = (G(J) - C(J) * X(J+1)) / W(J) END DO END SUBROUTINE TriDiag END PROGRAM CrankNicolson Output: X = T 0.00 0.01 0.02 ... 0.10
0.1000
0.2000
0.3000
0.4000
0.5000
0.2000 0.1988 0.1936
0.4000 0.3955 0.3789
0.6000 0.5834 0.5396
0.8000 0.7381 0.6460
1.0000 0.7690 0.6920
0.0948
0.1803
0.2482
0.2918
0.3068
Note the use of array sections inthe main program. Note also that the subroutine TriDiag can be used to solve any tridiagonal system, and could be made part of ageneral utility module.
Chapter 16 Summary • • •
A numerical method is an approximate computer method for solving a mathematical problem which often has no analyticalsolution. A numerical method is subject to two distincttypes of error: rounding error in the computer solution, and truncation error, where an infinite mathematical process,like taking a limit,is approximated by a finite process. An external or module procedure may be passed as an argument of a procedure. An interface block isrecommended.
245
Chapter 16 Exercises 16.1 Use Newton's method in a program to solve some of the following (you may have to experiment a bit with the starting value): (a)x − x = 10 (to real and two complex roots) 4
(b)e
−x
= sin x (infinitely many roots)
(c)x − 8 x + 17 x − 10 = 0 (three realroots) 3
2
(d)log x = cos x
(e)x − 5x − 12 x + 76 x − 79 = 0 (two realroots near 2;find the complex roots as well.) 4
3
2
16.2 Use the Bisection method to find the square root of 2,taking 1 and 2 as initial values of x L and x R . Continue bisecting until the maximum error is less than 0.05. Use Inequality 16.2 to determine how many bisections are needed. 16.3
Use the Trapezoidalto evaluate ∫
4
0
x 2 dx
using a step-length of h = 1.
16.4 A human population of 1000 attime t = 0 grows at arate given by
dN / dt = aN ,
where a = 0.025 per person per year. Use Euler's methodto projectthe population overthe next 30 years, working in steps of (a) h = 2 years,(b) h = 1 year and (c) h = 0.5 years. Compare your answers with the exact mathematical solution. 16.5 The basic equation formodelling radio-active decay is
dx / dt = − rx ,
where x isthe amount ofthe radio-active substance attime t,and r isthe decay rate. Some radio-activesubstances decayinto otherradio-activesubstances, whichinturn also decay. For example, Strontium 92 (r1 = 0.256 per hr) decaysinto Yttrium 92 (r2 = 0.127 per hr), whichinturn decays into Zirconium. Write down a pair of differential equations for Strontium and Yttrium to describe whatis happening. 26
Starting at t = 0 with 5x10 atoms of Strontium 92 and none of Yttrium, use the Runge-Kutta formulaeto solvethe equations up to t = 8 hoursin steps of 1/3 hours.Also use Euler's method for the same problem, and compare your results. 16.6 The impala population x(t)in the Kruger National Park in South Africa may be modelled by the equation dx/dt = (r - bx sin at)x, where r, b, and a are constants. Write a program which:
•
•
•
•
reads values for r, b, a and the step-length h (in months); reads the initial value of x and t; uses Euler's method to compute the impala population; printsthe population at monthly intervals over a period oftwo years.
16.7 The luminous efficiency (ratio ofthe energy in the visible spectrum to the total energy) of a black body radiator may be expressed as a percentage by the formula
E = 64.77Τ −4 ∫
7 ×10−5
4 ×10
246
−5
(
)
x −5 e1.432 / Τx − 1 dx −1
where T isthe absolutetemperaturein degrees Kelvin, x isthe wavelengthin cm, and the range of integrationis overthe visible spectrum. Taking T = 3500°K,use Simpson'sruleto compute E,firstly with 10 intervals(n = 5), and then with 20 intervals (n = 10), and compare your results. 16.8 Van der Pol's equation is a second-order non-linear differential equation which may be expressed astwo first-order equations as follows:
dx1 / dt = x2
(
)
dx2 / dt =∈ 1 − x12 x2 − b 2 x1 trajectory of the solution (the plot of x1 against x2 ) starting at any pointin the positive x1 − x2 plane, it always moves continuously into the same closed loop. Use the Runge-Kutta method to
The solution of this equation has a stable limit cycle, which means that if you plot the phase solve this system numerically, with h = 0.1, x1 (0) = 0 , and x2 (0) = 1 .If you have access to graphics facilities, draw the phase trajectory for b = 1 and ∈ ranging between 0.01 and 1.0.
247
Appendix B Summary of Fortran 90 Statements Statements A through B ALLOCATABLE specifiesthe ALLOCATABLE attribute foran array. See REAL. ALLOCATE allocates dynamic storage to a pointer variable atrun-time, e.g. REAL, POINTER :: P1, P2(:) ALLOCATE( P1, P2(100) ) It may also be used to allocate memory to an allocatable array: REAL, ALLOCATABLE :: X READ*, N ALLOCATE( X(N) ) In general: ALLOCATE( list[, STAT = st] ) Ifthe STAT specifieris present, st is given the value zero after a successful allocation, and a positive value otherwise (in which case execution continues).If STAT isabsent,execution stops after an unsuccessful attemptto allocate. ASSIGN (obsolescent and not recommended) is used in conjunction with the assigned GO TO. E.g. ASSIGN 5 TO N ... GOTO N [(4, 5, 6)] willtransfer controlto statement 5 afterthe execution ofthe GOTO. BACKSPACE positions a filebefore the preceding record, e.g. BACKSPACE 2
! file is connected to unit 2
BACKSPACE( [UNIT =] u[, IOSTAT = io][, ERR = label] ) See READ forthe meaning ofthe specifiers. BLOCK DATA (not recommended) names a BLOCK DATA program unitfor the initialization of objectsin named COMMON blocks: BLOCK DATA Rubbish COMMON / NAME / X, Y, X DATA X, Y, X / 1, 2, 3 /
248
END BLOCK DATA Rubbish
Statements C through D CALL invokes a subroutine: CALL PLONK CALL PLINK( A, B, C ) CASE allows a selection of various options: SELECT CASE (Ch) CASE ("a":"z")
! CASE (low:high)
PRINT*, "lower case" CASE ("A":"Z") PRINT*, "UPPER CASE" CASE DEFAULT PRINT*, "not a char" END SELECT One of the bounds may be absent, e.g. CASE (:0) selects non-positive numbers. The full definition isin Chapter 6. CHARACTER specifies charactertype. The declaration has a number of forms, e.g. CHARACTER*4 Word
! Word has length 4
CHARACTER (LEN = 8) Names(100) ! array of 100 names ! each of length 8 CHARACTER (4) N, Line*80
! N has length 4, Line has ! length 80
CHARACTER (LEN = 20, KIND = 2) GreekWord CHARACTER (*), INTENT(IN) :: Name
! assumed length ! dummy argument
CHARACTER (*), PARAMETER & :: Message = "No such file" ! named constant
249
CHARACTER isthe only one of the five intrinsictypes to have two parameters:length and kind. CLOSE disconnects a filefrom a unit,e.g. CLOSE( 13 ) In general: CLOSE( [UNIT =] u[, IOSTAT = io][, ERR = label] & [, STATUS = st] ) See OPEN forthe meanings of the firstthree specifiers. st is a character expression which must have the value KEEP or DELETE. This specifies what happenstothe fileafter disconnection. st defaultsto KEEP, unlessthefile has status SCRATCH, in which case its only value is DELETE. COMMON (not recommended)allocates memoryin a COMMON block ofstorage, which may be blank or named. The blocks may be accessed from different program units, using the same or different variable names. E.g. COMMON /JUNK/ A, B, X(5) in one program unit,and COMMON /JUNK/ X, Y(4), Z1, Z2 in another, meansthat A and X, B and Y(1),..., X(5) and Z2 sharethe same storagelocations. As you canimagine,thiscan be highly dangerous.If data must be shared between program units, itshould be declared in a module accessed by any program units needing it. Blank COMMON referstothe unnamed COMMON block, ofwhich there isonly one: COMMON M, G COMPLEX specifies complex type: COMPLEX X X = (0, 1)
! sqrt(-1)
Complex constantsinlist-directed input with READ* mustbe in parentheses. CONTAINS signalsthe presence of one ormore internal or module subprograms. CONTINUE is a dum my statement which does nothing.Itsmain usage wasas alabelled statement at the end of a DO loop: DO 10 I = 1, 100 ... 10
CONTINUE
Thisis not recommended; use DO with END DO instead.
250
CYCLE (not recommended)transfers controltothe END DO statement ofthe current DO construct. The nextiteration(ifthereis one)isinitiated.If you want toleave out partof a loop sometimes you should rewriteit. DATA initializes objects during compiletime. Thisis particularly usefulfor arrays: REAL A(10), X(5), B, C, D DATA A / 10 * 1 /[,] (X(I), I = 2, 4) / 1, 2, 3 / DATA B, C, D / 4, 5, 6 / Note the optional comma separating a value listfrom a following objectlist. DEALLOCATE releases dynamic storage: DEALLOCATE( P1, P2 ) In general: DEALLOCATE( list[, STAT = st] ) See ALLOCATE forthe analogous meaning of STAT. DIMENSION declares an array.Itis notrecom mended as a separatestatement. See REAL forits use as an attribute. DO repeats a block of statements a specified number oftimes, e.g. DO I = 1, 100
! I incremented by 1 by default
... END DO and DO K = 10, 1, -2
! K decremented by 2
... END DO
DO may also be used with a conditional EXIT, e.g. DO IF (ABS( F(X) ) < 1E-6) EXIT ... END DO
251
DO parameters should be integers. The use of real parameters is obsolescent and not recommended. The full definition of DO isin Chapter 7. DO WHILE repeats a block of statements conditionally: DO WHILE (ABS( F(X) ) >= 1E-6) ... END DO Metcalf and Reid warn that DO WHILE may be inefficient when execution time is a critical factor. Since most examplesin this book do notfallinthis category,I have used itin preference to DO with EXIT. It makes the logic much clearer. DOUBLE PRECISION (not recommended) specifies a real variable with a precision higher than the default: DOUBLE PRECISION X It is the Fortran 77 user's cop out for not learning about kind type parameters, which are discussed fully in Chapter 3.
Statements E through F END isthe finalstatementin a program unitor subprogram. ENDFILE writes an endfile record to a sequentialfile.In general: ENDFILE( [UNIT =] u[, IOSTAT = io][, ERR = label] ) The specifiershave the same meaning asin OPEN. ENTRY (not recommended) allows a subprogram to be entered at points other than at the beginning, and therefore defeatsthe purpose of writing subprograms aslogical units: SUBROUTINE JUNK( dummy-arglist ) ... ENTRY SILLY( dummy-arglist ) ... ENTRY WORSE( dummy-arglist ) ... END SUBROUTINE You can then call JUNK, SILLY or even WORSE, depending on exactly where you would liketo start! EQUIVALENCE (not recommended) enablestwo or more objectsinthesame program unitto share the same storage area. E.g.
252
EQUIVALENCE (A, B), (X, Y) allows A and B on the one hand, and X and Y on the other,to sharethe same storage area. Since array elements occupy consecutive storage locations, you can get some really weird results. E.g. INTEGER A(2), B(3), X(2,2) EQUIVALENCE (A(2), B(1), X(1,2)) implementsthe following arrangement (elementsinthe same column share storage): A(1)
A(2) B(1) B(2) B(3) X(1,1) X(2,1) X(1,2) X(2,2) If you wantto use different names forthe same object,setup an alias with a pointer. EXIT (conditionally recommended) allows exitfrom a DO construct(see example under DO). You should exitfrom as closetothetop or bottom of a DO as possiblein orderto makethe exitcondition easy to see. Multiple exits are definitely not recommended. EXTERNAL specifies each name listed as the name of an external or dum my procedure. The interface remains implicit. If an explicit interface is needed, use an INTERFACE block; this is generally recom mended. E.g. EXTERNAL F FORMAT provides an I/O format specification. Itis described fully in Chapter 10. See PRINT for examples. FUNCTION names a function subprogram: FUNCTION Factorial( N ) ... END FUNCTION Factorial In the case of a recursive function the form is,e.g. RECURSIVE FUNCTION Factorial( N ) RESULT (Fact) The type can be specified inthe FUNCTION statement, asin INTEGER FUNCTION Factorial( N )
Statements G through H GOTO (not recommended) transfers control unconditionallyto alabelled statment: GOTO 70 There are two other forms of GOTO: assigned GOTO (see ASSIGN) and computed GOTO. The computed GOTO looks like this: GOTO ( 20, 50, 10, 40 ) N Control passestothe statement withthe Nthlabelinthelist,e.g.tothe statementlabelled 10 if N evaluatesto 3.
253
Statements I through K IF transfers control conditionally. There are three distinctforms.
•
The "logical" IF statement is used when a single statementis to be executed under a certain condition: IF (A /= 0) X = B / (2 * A)out
•
The IF construct is used when blocks of statements areto be executed under certain conditions: IF (Num > 0) THEN PRINT*, "positive" ELSE IF (Num == 0) THEN PRINT*, "zero" ELSE PRINT*, "negative" END IF
•
The "arithmetic" IF is a
dangerous statement, since its use tends to be coupled with the occurrence of numerous GOTO statements---A. Balfour and D.H. Marwick, Programming in Standard FORTRAN 77 (Heinemann, London, 1979,p. 291) Itis obsolescent and not recommended. E.g. IF (B**2 - 4*A*C) 10, 20, 30
Control passes to statements 10, 20, or 30 according as B**2 - 4*A*C is negative, zero, or positive. IMPLICIT (not recommended) declares variables of a specified type according to their initial letter. E.g. IMPLICIT INTEGER (A, X-Z) specifiesintegertype for allvariablesstarting withtheletters A, X, Y and Z.Itis betterto specify the type of each variable separately in atype declaration statement. IMPLICIT NONE suspends theimplicittype rule, whereby all variables withtheinitialletter I to N inclusive are specified as integers, with all others real. This statement should appear in every program unitto force you to declare all objects specifically. INCLUDE (not recommended) enables text from another file to be included in the source file during compilation.Itis nottechnically a Fortran statement,and has the form INCLUDE "filename"
254
INQUIRE ascertainsthe status and attributes of a file.Ithasthreeforms:inquire by I/O list,inquire by file and inquire by unit. Inquire by I/O listreturnsthe length of an unformatted outputrecord by means ofthe IOLENGTH specifier, e.g. INQUIRE( IOLENGTH = reclen ) Student reclen can then be used to give the record length with the RECL specifier of an OPEN statement. The othertwo forms are INQUIRE( FILE = filename, spec-list )
! by file
INQUIRE( [UNIT =] u, spec-list )
! by unit
where filename and u are characterand integer expressionsrespectively.spec-list is a list of optional specifiers. Their names, and values returned, are (char means character): EXIST (logical): TRUE if it exists, FALSE otherwise. OPENED (logical): TRUE if connected, FALSE otherwise. NUMBER (integer): value of unit number connected, or -1 if no unit is connected. NAMED (logical): TRUE if file has a name, FALSE otherwise. NAME (char): returns name if file has a name. ACCESS (char): SEQUENTIAL, DIRECT, or UNDEFINED (if there is no connection). SEQUENTIAL and DIRECT (char): YES, NO or UNKNOWN, depending on allowed mode of access. FORM (char): FORMATTED, UNFORMATTED, or UNDEFINED. RECL (integer): maximum record length allowed. NEXTREC (integer): number of most recent record read or written. BLANK (char): NULL or ZERO depending on whether blanks in numeric fields are interpreted by default as null fields or zeros. POSITION (char): REWIND, APPEND, ASIS or UNDEFINED—see OPEN. ACTION (char): READ, WRITE, READWRITE or UNDEFINED. READ, WRITE and READWRITE (char): YES, NO or UNKNOWN. DELIM (char): APOSTROPHE, QUOTE, NONE or UNKNOWN—see OPEN. PAD (char): YES or NO—see OPEN. E.g. LOGICAL connected CHARACTER(10) acc INTEGER nrec INQUIRE( 1, OPENED = connected, ACCESS = acc, NEXTREC = nrec ) INTEGER declares objects withintegertype, e.g. INTEGER N, X INTEGER List(0:100) See REAL forattributes which may be specified.
255
INTENT specifiesthe intent attribute for a dum my argument. See REAL. INTERFACE specifies an explicitinterface for an external subprogram, e.g. INTERFACE FUNCTION F(X) REAL F REAL, INTENT(IN) :: X END FUNCTION F END INTERFACE Interface blocks can also overload procedures with a generic name: INTERFACE SuperFung MODULE PROCEDURE IntFung, RealFung
! defined in module
END INTERFACE Procedures may be overloaded with an operator, e.g. INTERFACE OPERATOR(*) FUNCTION MyMult( A, B )
! must be a function
TYPE (MyType) MyMult TYPE (AnotherType), INTENT(IN) :: A, B END FUNCTION MyMult END INTERFACE and also with the assignment operator: INTERFACE ASSIGNMENT(=) SUBROUTINE MyAss( Left, Right ) TYPE (MyType), INTENT(IN) :: Left TYPE (AnotherType), INTENT(IN) :: Right END SUBROUTINE END INTERFACE INTRINSIC specifiesthata name listedisthat of anintrinsic procedure.The statement is normally optional, but makesitclear tothe reader(who may be unfamiliar with the plethora of new intrinsic procedures available under Fortran 90) which procedures areintrinsic and which are not.
256
An intrinsic procedure which is passed as an argument must be specified in an INTRINSIC statement.
Statements L through N LOGICAL declareslogicaltype: LOGICAL Switch LOGICAL TruthTable(4,4)
! array of logical elements
See REAL forattributes which may be specified. MODULE defines a module: MODULE Clobber ... END MODULE Clobber NAMELIST is an obscurefeature which enables you to specifyintheinputstream which items in a NAMELIST group areto be read. E.g. INTEGER A, B, C NAMELIST /MyLot/ A, B, C READ( *, [NML =] MyLot )
Input stream: MyLot A = 3 C = 39 (a value for B has been omitted). See Chapter 10 for another example. NULLIFY gives a pointer variable disassociated status, which may be tested for by the ASSOCIATED intrinsic function, e.g. NULLIFY( P1 )
Statements O through P OPEN connectsan externalfileto a unit. Thefilecan be createdfirstifnecessary.Itcan also change some properties of a connection. The generalform is OPEN( [UNIT =] u, spec-list ) where u isthe unit number. The specifiersin spec-list are (char means character): IOSTAT (integer): returns zero if the statement successfully executes, and a positive value otherwise.
257
ERR (integer constant):labelof statementto which controlpasses if an error occurs. FILE (char):providesfile name;ifthisspecifieris omitted,the STATUS specifier mustbe setto SCRATCH, and the fileis deleted when the connection is closed. STATUS (char): OLD (file must already exist), NEW (file must not exist, but is created), REPLACE (iffile does not existitis created,ifit does existitis deleted and a new one created), SCRATCH (fileis created, and deleted when connection is closed), UNKNOWN. ACCESS (char): SEQUENTIAL (default), DIRECT. FORM (char): FORMATTED (default for sequential access), UNFORMATTED (defaultfor direct access). RECL (positiveinteger):recordlength for direct access(obligatory), maximum recordlength for sequential access (optional);for formatted files length is number of characters in record, for unformatted files length is system dependentbut may be found with INQUIRE. BLANK (char): NULL (default), ZERO; sets defaultforinterpretation of blanks as nulls or zeros; formatted records only. POSITION (char): ASIS (default—file is opened at previous position), REWIND (opened at initial position), APPEND (opened ahead of endfile record);sequential access only. ACTION (char): READ (read only), WRITE (write only), READWRITE (both); defaultissystem dependent. DELIM (char): APOSTROPHE, QUOTE, NONE (default);indicates delimiter character used for character constants with list-directed or NAMELIST formatting. PAD (char): YES (default—formatted inputrecord regarded as padded with blanks if input list and associated format specify more datathan appearin record), NO. E.g. OPEN (2, FILE = "Students", ACCESS = "DIRECT", & STATUS = "OLD", RECL = 40)
OPTIONAL specifiesthe OPTIONAL attributefor dummy arguments. See REAL. PARAMETER specifiesthe PARAMETER attributeto name a constant. See REAL. PAUSE (obsolescent and not recommended) suspends execution pending externalintervention. POINTER specifiesthe POINTER attribute,e.g. REAL, POINTER :: P REAL, TARGET :: R ... P => R
! P is an alias for its target R
It may also be used to allocate dynamic storage: REAL, POINTER :: X(:) ...
258
ALLOCATE( X(N) ) PRINT sends outputtothe standard outputunit. Output may be formatted orlist-directed: PRINT*, "The answer is:", X + Y
! list-directed
PRINT "(A, F5.2)"”, "The anser is:", X PRINT 10, "The anser is:", X 10
! labelled format
FORMAT( A, F5.2 )
PRINT*, ((A(I,J), J = 1, N), I = 1, N)
! implied DO
PRIVATE specifies the PRIVATE attribute for some or all of the entities in a module, and for components of derived types.See REAL and TYPE. PROGRAM optionally names a program: [PROGRAM MyOne] ... END [PROGRAM [MyOne]]
! name can't appear without PROGRAM
PUBLIC specifiesthe PUBLIC attribute for module entities. See REAL.
Statements R through S READ transfers data from an input device.Ithas a number offorms, e.g. READ*, A, B, C device
! list-directed from standard input
READ (*, *) A, B, C device
! list-directed from standard input
READ (5, *) A, B, C
! list-directed from unit 5
READ (1, 15) A, B, C
! from unit 1, format labelled 15
15 FORMAT( 3F6.2) READ( *, “(3F6.2)” ) A, B, C ! from standard input device READ (1) A, B, C
! from unit 1, unformatted
The general form is: READ ([UNIT =] u, [FMT =] fmt [,spec-list] ) [list]
259
The specifiers may be in any order,subject tothe following conditions:ifthe UNIT keyword is omitted, u must be first; if the FMT keyword is omitted, fmt must be second, following u withoutits keyword. The other specifiers are: IOSTAT (integer):returns a negative value if end-of-record encountered during non-advancing input,a different negative value if end-of-file detected,a positive valueifan erroris detected, or zero otherwise. END = n: control passesto statementlabelled n when end-of-file detected. ERR = n: control passesto statementlabelled n when an erroris detected;labelsfor END and ERR may be the same; if END and ERR labels are not specified and an exception occurs, the program will crash unless IOSTAT is specified. REC (integer):specifies record number to be read during direct access. NML (name):replaces the FMT specifier; name isthe name specified in a NAMELIST group. E.g. READ( 2, REC = 75, IOSTAT = IO ) Student
In addition, non-advancing input may be specified with ADVANCE = "NO" (default YES). In this case,two additional specifiers are available: EOR = n: control passesto statement n when an end-of-record condition occurs. SIZE (integer):returns the number of characters actually read. The unitspecifier can be an internalfile, denoted by a character variable: CHARACTER (4) BUFFER READ (BUFFER, "(I4)" ) YEAR
REAL declares objects with realtype. It has a number of forms, e.g. REAL [::] A
! colons optional
REAL :: B = 10
! initialization; colons obligatory
REAL X(0:10)
! array
The following attributes may be specified in a type declaration: ALLOCATABLE, DIMENSION, EXTERNAL, INTENT, INTRINSIC, OPTIONAL, PARAMETER, POINTER, PRIVATE, PUBLIC, SAVE, TARGET. Most attributes may be specified with any of the intrinsic types (CHARACTER, COMPLEX, INTEGER, LOGICAL and REAL) or a derived type. Attributes may specified in separate statements, e.g. REAL P, Q, R, S POINTER P, S TARGET Q, R
260
A double colon must appear whenever there is an initialization expression, or an attribute is specified.If a constantis named with the PARAMETER attribute,there must be an initialization expression. Array bounds may be specified after a name, instead of with the DIMENSION attribute. E.g. REAL, PARAMETER :: g = 9.8
! named constant
INTEGER, PARAMETER :: Max = 100 REAL, DIMENSION(Max) :: X INTEGER :: N(Max) = (/ (I, I = 1, Max) /)
! array constructor
INTEGER, ALLOCATABLE :: Network(:,:) REAL, DIMENSION(10) :: A, B(5), C(4,4)
! only A is rank 1 ! size 10
REAL, OPTIONAL, INTENT(IN) :: Y
! optional dummy argument
REAL, INTENT(INOUT) :: M
! dummy only
Certain (fairly obvious) combinations of attributes are not allowed, e.g. POINTER on the one hand and TARGET, orINTENT on the other; TARGET and PARAMETER; POINTER and ALLOCATABLE. A kind parameter may be specified for any type: RECURSIVE specifies a recursive procedure. See FUNCTION. RETURN returns controlfrom a subprogram at a point otherthanits END statement. This canleadto unstructured design,and should be avoidedif possible. Thereis anotherform of RETURN calledthe "alternate" RETURN, which is obsolescent and not recommended, because it allows returns to alternate points inthe calling program:... CALL GUNGE( A, B, C, *10, *30 ) ... CONTAINS SUBROUTINE GUNGE( X, Y, Z, *, * ) ... RETURN 1 ... RETURN 2 ... END SUBROUTINE GUNGE END
261
Ifthe integer expression in the RETURN statement islessthan 1 or greaterthan the number of asterisks in the dum my argument list, a "normal" return is executed (i.e. to the point of call). Otherwise,ifithasthe value i,control passestothe statementinthe calling program whoselabel isthe actualargumentcorrespondingtothe ith dum my asterisk. So RETURN 1 effectsa returnto statement 10, while RETURN 2 returns to statement 30. REWIND repositions a sequentialfile atitsinitial point. The syntax isthe same as for backspace, e.g. REWIND 3 REWIND( 2, IOSTAT = IO ) SAVE specifies the SAVE attribute for local variables declared in subprograms,i.e. such variables retain their current values between calls. See REAL. All variables which have been initialized acquirethe SAVE attribute automatically. SELECT CASE See CASE. SEQUENCE (not recommended) specifies the SEQUENCE attribute for derived types. Two type definitions in different scoping units define the same data type if they have the same name and components, and if both have the SEQUENCE attribute (giving them what is called storage association).Itis betterto have a single definition in a module accessibleto both scoping units. STOP (not recommended) stops program execution. Thisis needed by people who want to stop their programs at places otherthan atthe END. SUBROUTINE names a subroutine: [RECURSIVE] SUBROUTINE NAME( A, B, C, \ldots ) ... END SUBROUTINE NAME
If there are no arguments, the name is written without parentheses: SUBROUTINE NONE
Statements T through Z TARGET specifiesthe TARGET attribute for an object which isthe targetof a pointer: REAL, TARGET :: R REAL, POINTER :: P1 ... P1 => R See also REAL. TYPE defines a derived type, e.g. TYPE Person
262
[PRIVATE]
! if no access allowed to components
CHARACTER (20) Name ... END TYPE Person
Objects of derived type may be declared, e.g. TYPE (Person), DIMENSION(:), INTENT(IN) :: Town TYPE (Person) Me
USE enables access to the entities in a module by use association: USE MyModule
! only one module per USE
USE YourModule
Other possibilities are: USE YourMod, MyPlonk => YourPlonk
! MyPlonk is an alias
! ... for object YourPlonk in the module USE USE YourMod, ONLY :: This, That ! access only to ! This and That
WHERE performs operations on selected array elements. There aretwo forms. The WHERE statement has the form REAL A(20,20) ... WHERE (A > 0) A = 1
! all elements > 0 replaced by 1
The WHERE construct looks like this: INTEGER A(20,20) ... WHERE (A > 0)
263
A = 1
! all positive elements replaced by 1
[ELSEWHERE A = 0]
! all the rest replaced by 0
END WHERE WRITE sends outputto an output unit.In general: WRITE ([UNIT =] u, [FMT =] fmt [,spec-list]) [list] The specifiersare the same as for READ, exceptthatthere is obviously no END specifier.E.g. WRITE (2, "(10F5.3)") (X(I), I = 1, N) WRITE (1, * ) "List directed output on unit 1" WRITE (3, REC = 76) A
! direct access write to record 76
Non-advancing WRITE is useful for writing prompts: WRITE (*, "(A)", ADVANCE = "NO") & "Enter a number: " ! not list-directed/ There are no EOR or SIZE specifiers for non-advancing output.
264
Appendix C Intrinsic Procedures Intrinsic Procedures C.1. Elemental Numeric Functions C.2. Elemental Character-handling Functions C.3. Non-elemental Character-handling Functions C.4. Functions Relating to Numeric Representation
•
•
Numericinquiry functions Elementalfunctions to manipulate reals
C.5. Bit Manipulation Functions •
•
•
Inquiry function Elementalfunctions Elemental subroutine
C.6. Vector and Matrix Multiplication Functions C.7. Array Reduction Functions
•
•
Optional argument DIM Optional argument MASK
C.8. Array Inquiry Functions C.9. Array Construction and Manipulation Functions C.10 Inquiry Functions for Any Type C.11. Elemental Logical Function C.12. Functions Relating to Kind C.13. Transfer Function C.14. Non-elemental Intrinsic Subroutines •
•
Random numbers Real-time clock
Intrinsic Procedures It is helpful to categorize intrinsic procedures as follows, although the descriptions below are grouped somewhat differently, for convenience of reference: •
•
Elemental procedures may be appliedto scalars or arrays. When applied toarrays,the operation isperformed on each elementofthe array. Arguments may berealor complex,unless otherwise stated, or unless the context clearly requires otherwise. Arguments must generally be of the same type. Inquiry functions properties oftheir arguments.
•
Transformational functions usually have array argumentsand an arrayresultdependingin some way on the elements ofthe arguments. Non-elemental subroutines.
•
Descriptions below are given with dum my arguments,so that optional arguments(indicated [thus]) may be passed using the dummy argument names as keywords.
265
Results are usually returned in the default kind, unless the KIND keyword is used (where appropriate). Trigonometricfunctions assume arguments are in radians,and return radians. Almost all of the procedures are functions. To highlightthe few that are subroutines the keyword CALL has been included in the description.
C.1. Elemental Numeric Functions Note thatthe arguments may be real or complex scalars orarrays, unless otherwise stated. ABS(A): absolute value ofinteger,real or complex A. ACOS(X): inverse cosine (arc cosine). AIMAG(Z): imaginary part. AINT(A [,KIND]): largest whole real number not exceeding its argument, e.g. AINT(3.9) returns 3.0. ANINT(A [,KIND]): nearest whole realnumber, e.g. ANINT(3.0) returns 4.0. ASIN(X): inverse sine (arc cosine).
ATAN(X): inverse tangent (arctangent),inthe range-π/2 to π/2.
ATAN2(Y, X): inverse tangent (arc tangent), as principal value of the argument of the complex number (X, Y),inthe range -π to π. CEILING(A): smallestinteger notlessthan A. CMPLX(X [,Y] [,KIND]): converts X or (X, Y)to complex type. CONJG(Z): conjugate of complex Z. COS(X): cosine. COSH(X): hyperbolic cosine. DIM(X, Y): max(X-Y, 0). EXP(X): exponentialfunction. FLOOR(A): largestinteger not exceeding its argument, e.g. FLOOR(-3.9) returns -4. INT(A [,KIND]): convertstointegertype,truncating towards zero. LOG(X): LOG naturallogarithm; for complex X resultisthe principal value. LOG10(X): com mon (base 10) logarithm. MAX(A1, A2 [,A3,...]: maximum of arguments. MIN(A1, A2 [,A3,...]: minimum of arguments. MOD(A, P): remainder of A modulo P,i.e.A-INT(A/P)*P. E.g. MOD(2.2, 2.0) returns 0.2. MODULO(A, P): A modulo P for A and P bothreal or bothinteger,i.e.A-FLOOR(A/P)*P inthe real case, and A-FLOOR(A÷P)*P in the integer case, where ÷ represents mathematical division. E.g. MODULO(-10, 3) returns 2, MODULO(-2.2, 2.0) returns 1.8. NINT(A [,KIND]): nteger nearestto A. REAL(A [,KIND]): function convertsto real. SIGN(A, B): absolute value of A times sign of B. SIN(A): sine. SINH(A): hyperbolic sine.
266
SQRT(A): square root. TAN(A): tangent TANH(A): hyperbolictangent.
C.2. Elemental Character-handling Functions Compilers must support the ASCII collating sequence, but may also support other collating sequences. ACHAR(I): character with ASCII code I for I inthe range 0–127 (see Appendix D). ADJUSTL(STRING): string of same length by changing leading blanks into trailing blanks (left justify). ADJUSTR(STRING): string of same length by changing trailing blanksinto leading blanks (right justify). CHAR(I [,KIND]): characterin position I ofthe system collating sequence with given kind. IACHAR(C): ASCII code ofcharacter C (see Appendix D). ICHAR(C): position of character C in the system collating sequence. INDEX(STRING, SUBSTRING [BACK]): starting position of SUBSTRING as a substring of STRING, or zeroifitdoes notoccur. The position ofthefirstorlastsubstringisreturned according as BACK is absent/FALSE or TRUE. LEN_TRIM(STRING): length of STRING withouttrailing blanks. LGE(STRING_A, STRING_B): TRUE if STRING_A follows STRING_B inthe ASCIIsequence or is equaltoit(i.e.is "lexically" greaterthan or equaltoit), FALSE otherwise. LGT(STRING_A, STRING_B): TRUE if STRING_A follows STRING_B in the ASCII sequence, FALSE otherwise. LLE(STRING_A, STRING_B):,TRUE if STRING_A precedes STRING_B in the ASCII sequence orisequaltoit, FALSE otherwise. LLT(STRING_A, STRING_B): TRUE if STRING_A precedes STRING_B in the ASCII sequence, FALSE otherwise. SCAN(STRING, SET [,BACK]): position of a character of STRING thatoccursin SET, or zero ifno such character. The position oftheleft-most orright-mostsuch characterisreturned according as BACK is absent/FALSE or TRUE. VERIFY(STRING, SET [,BACK]): zero if each character of STRING appearsin SET, or the position of a character of STRING thatis not in SET. The position of the left-most orright-most such characterisreturned according as BACK is absent/FALSE or TRUE.
C.3. Non-elemental Character-handling Functions LEN(STRING): (inquiry function) number of charactersin STRING if scalar, orin an element of STRING ifitis an array. REPEAT(STRING, NCOPIES): concatenation of NCOPIES of STRING; both arguments scalar. TRIM(STRING): STRING (scalar) with trailing blanks removed.
C.4. Functions Relating to Numeric Representation These functions relate to the models used to represent integers and reals internally. The parameters of the models may vary from processor to processor. An example of a model for the set of integers i represented is:
267
i = ± ∑ w k × 2 k −1 q
k =1
where wk is 0 or 1.
An example of the representation of reals x is:
p x = 0 or ± 2 1 / 2 + ∑ f k × 2 − k k =2 where −126 ≤ e ≤ 127, for example, and f k is 0 or e
1. Values for p and q could be 24 and 31, for example. A base other than 2 might also be used.
Numeric inquiry functions Arguments may be scalars orarrays. The value ofthe argument need notbe defined. DIGITS(X): number of significant digitsin the model for real orinteger X, i.e. p or q. EPSILON(X): numberthatisalmost negligible compared with 1 inthe modelthatincludesreal X, i.e. 2
1− p
.
(1 − 2 )2 −p
HUGE(X): largest value inthe modelthatincludes real orinteger X,i.e.
127
for reals.
MAXEXPONENT(X): maximum exponent (integer)inthe modelthatincludes real X,i.e.127. MINEXPONENT(X): minimum exponent (integer)inthe modelthatincludes real X,i.e.–126. PRECISION(X): decimal precision (number of decimal places)for realor complex X. RADIX(X): RA DIX base (integer)inthe modelthatincludes real orinteger X,i.e. 2. RANGE(X): decimal exponent range in the modelthatincludes integer,real or complex X. TINY(X): smallest positive number inthe modelthatincludes real X,i.e. 2
−127
.
Elemental functions to manipulate reals EXPONENT(X): EXPONENT exponent (integer) part e ofthe model forX. FRACTION(X): FRACTION fractional part ofthe model for X,i.e. X 2
−e
.
NEAREST(X, S): NEAREST nearest different machine numberin direction given by sign of real S. RRSPACING(X): RRSPACING reciprocal of relative spacing of model numbers near X, i.e.
X 2 −e 2 p
. I
SCALE(X, I): SCALE X 2 (real). SET_EXPONENT(X, I):, real whose sign and fractionalpartarethose of X and whose exponent partisI,i.e. X 2
I −e
.
SPACING(X): absolute spacing of modelnumbers nearX, i.e 2
268
e− p
.
C.5. Bit Manipulation Functions These are based on an integer model like the one in Section C.4.
Inquiry function BIT_SIZE(I):, maximum number of bitsthat may be held in the modelfor I.
Elemental functions BTEST(I, POS): TRUE ifbit POS ofinteger I has value 1. IAND(I, J): logical AND on all corresponding bits of I and J. IBCLR(I, POS): value ofI with bit POS cleared to zero. IBITS(I, POS, LEN): value equalto LEN bits of I starting at bit POS. IBSET(I, POS): value ofI with bit POS setto 1. IEOR(I, J): logical exclusive OR on allcorresponding bits of I and J. IOR(I, J): logicalinclusive OR on all corresponding bits of I and J. ISHFT(I, SHIFT): value of I with bits shifted SHIFT places to left (right if negative) and zerosshiftedin from otherend. Since shifting allthe bitsof aninteger one positiontotheleft(right) multiplies(divides)itby 2 this provides a much faster means of multiplying (dividing) by powers of 2. E.g. ISHFT( 2, 4 ) returns 16, and ISHFT( 2, -1 ) returns 1. ISHFTC(I, SHIFT [,SIZE]): value of I with SIZE right-most bits shifted circularly SHIFT places toleft(rightifnegative);if SIZE is absentall bits are shifted. NOT(I): logical complement of all bitsin I, i.e. allthe bits of I are flipped.
Elemental subroutine CALL MVBITS(FROM, FROMPOS, LEN, TO, TOPOS): copies the sequence of bits in FROM that start at position FROMPOS and haslength LEN,to TO, starting at position TOPOS.
C.6. Vector and Matrix Multiplication Functions DOT_PRODUCT(VECTOR_A, VECTOR_B):, scalar(dot) productforrealand integerarguments. Both arguments must be rank-one and the same size.Ifthe arguments are logical, ANY(VECTOR_A .AND. VECTOR_B) isreturned. MATMUL(MATRIX_A, MATRIX_B): matrix product. For numeric arguments, there are three possible cases (arguments have been shortened to A and B): •
•
•
A is(n,m), B is (m,k),resultis(n,k); A is(m), B is(m,k),resultis(k); A is(n,m), B is (m),resultis(n).
E.g.inthe first case, element (I,J) ofthe resultis SUM(MATRIX_A(I,:) * MATRIX_B(:,J)) Ifthe arguments arelogical,SUM and * are replaced by ANY and .AND..
C.7. Array Reduction Functions The following seven functions all have array arguments. MASK is a logical array, e.g. an array expression. ALL(MASK): TRUE if all elements of MASK are true, otherwise FALSE.
269
ANY(MASK): TRUE if any elements of MASK are true. COUNT(MASK): number oftrue elements of MASK. MAXVAL(ARRAY): element with maximum value in real or integer ARRAY. If ARRAY has zero size,largest negative value on system is returned. MINVAL(ARRAY): element with minimum value in real or integer ARRAY. If ARRAY has size zero,largest positive value on system isreturned. PRODUCT(ARRAY): productof elements ofinteger,real or complex array, or 1 if ARRAY has size zero. SUM(ARRAY): sum of elements ofinteger,real or complex array, or
Optional argument DIM Allthesefunctionstake an optionalsecond argument DIM. Ifitis present,the operationis performed on allrank-one sections spanning through dimension DIM, and returns an array of rank reduced by 1. E.g. INTEGER :: A(2,3) = RESHAPE( (/ 1,2,3,4,5,6 /), (/2,3/) ) PRINT*, SUM(A,2) produces the output 9 12.
Optional argument MASK MAXVAL, MINVAL, PRODUCT and SUM take MASK as a third optional argument. The operation is then appliedto elements of ARRAY corresponding totrue elements of MASK (which must obviously have the same shape).
C.8. Array Inquiry Functions ALLOCATED(ARRAY): TRUE if ARRAY is currently allocated. LBOUND(ARRAY [,DIM]): rank-one array holding lower bounds if DIM is absent; otherwise lower bound in dimension DIM. SHAPE(SOURCE): rank-one array holding shape of SOURCE.If SOURCE is scalar,result has size zero. SIZE(ARRAY [,DIM]): (scalar) size of ARRAY if DIM is absent; otherwise extent along dimension DIM. UBOUND(ARRAY [,DIM]): similarto LBOUND exceptthatitreturns upper bounds.
C.9. Array Construction and Manipulation Functions Note that array elements are manipulated in array element order. CSHIFT(ARRAY, SHIFT [,DIM]): returns an array of the same shape and type as ARRAY with every rank-one section that extends across dimension DIM shifted circularly SHIFT times.If DIM is omitted it has the value 1. If SHIFT is an array it must have the shape of ARRAY with dimension DIM omitted,and suppliesa separate valueforeach shift.Some experiments should make this clear! EOSHIFT(ARRAY, SHIFT [,BOUNDARY] [,DIM]): identical to CSHIFT except that values are shifted off at the end (end-off shift) and boundary values inserted into the vacated positions.If ARRAY has an intrinsictype, BOUNDARY may be omitted; values of zero, FALSE, or
270
blank are shifted in as the case may be.If BOUNDARY is present and scalar,itsupplies all needed values;ifitis an array,it musthavethe shape of ARRAY with dimension DIM omitted,and supplies a separate value for each shift. MAXLOC(ARRAY [,MASK]): returns the subscripts ofthe largest element of ARRAY in a rankone array of size equaltotherank of ARRAY. The operation isrestrictedto elements corresponding to true elements of MASK if it is present. If there is more than one maximum, the first in array element orderistaken. MERGE(TSOURCE, FSOURCE, MASK): (elemental function) returns TSOURCE if MASK is TRUE, FSOURCE otherwise. E.g. if the three arguments are conformable arrays,the firsttwo are merged underthe control of MASK. MINLOC(ARRAY [,MASK]): similar to MAXLOC except that the subscripts of the smallest element are returned. PACK(ARRAY, MASK [,VECTOR]): rank-one array of elements of ARRAY according to true elements of MASK,if VECTOR is absent. Otherwiseresulthassize equalto size n of VECTOR, which must have sizeatleastequaltothe number ofselected elements t;if t < n, elements i ofthe resultfor i > t arethe corresponding elements of VECTOR. RESHAPE(SOURCE, SHAPE [,PAD] [,ORDER]): array with shape given by rank-one integerarray SHAPE andtype of SOURCE. The size of SHAPE must be constant.If PAD and ORDER are absent,the elements oftheresultarethe elements of SOURCE (in array element order).If PAD is present,it mustbe an array ofthe same type as SOURCE; copies of PAD areinsertedinto the result after SOURCE. ORDER must be an integer array withthe same shape as SHAPE.Its value must be a permutation of (1, 2,..., n).Itappearsto controlthe way in which SOURCE and PAD are combined. SPREAD(SOURCE, DIM, NCOPIES): makes NCOPIES duplicates of SOURCE by increasing itsrank by 1. DIM isthe dimension oftheresultalong which duplicationtakes place. See Chapter 15 for a program which generates examples. TRANSPOSE(MATRIX): transpose of rank-two array MATRIX. UNPACK(VECTOR, MASK, FIELD): array of type of VECTOR and shape of MASK. VECTOR must be rank-one array of size atleastthe number of true elements of MASK. The element of the result corresponding to the ith true element of MASK is the ith element of VECTOR; all others are equalto corresponding elements of FIELD ifitis an array (with the same shape as MASK), or to FIELD ifitisa scalar.
C.10. Inquiry Functions for Any Type ASSOCIATED(POINTER [,TARGET]): If TARGET is absent,result is TRUE if POINTER is associated with a target, FALSE otherwise. The status of POINTER must not be undefined. If TARGET is present,resultis TRUE if POINTER is associated withit.If TARGET itselfis a pointer, itstargetis compared with the target of POINTER, and FALSE is returned if either POINTER or TARGET is disassociated. PRESENT(A): TRUE ifthe actualargument corresponding tothe dummy argument A is presentin the current callto a subprogram. ASSOCIATED(POINTER [,TARGET]): If TARGET is absent,result is TRUE if POINTER is associated with a target, FALSE otherwise. The status of POINTER must not be undefined. If TARGET is present,resultis TRUE if POINTER is associated withit.If TARGET itselfis a pointer, itstargetis compared with the target of POINTER, and FALSE is returned if either POINTER or TARGET is disassociated. PRESENT(A): TRUE ifthe actualargument corresponding tothe dummy argument A is presentin the current callto a subprogram.
C.11. Elemental Logical Function
271
LOGICAL(L [,KIND]): function converts between kinds oflogical value. Returnsthe value of logical L (with a kind parameter value of KIND, ifitis present).If KIND is present, it must be a scalarinitialization expression.
C.12. Functions Relating to Kind KIND(X): kind parameter value of X.
−10
< n < 10
SELECTED_INT_KIND(R): kind parameter value for an integer datatype able to represent all integer values n in the range such kind is available.
R
R
, where R is a scalarinteger.–1 isreturnedif no
SELECTED_REAL_KIND([P] [,R]): kind parameter for a real data type with decimal precision at least P, and decimal exponent range at least R (as returned by PRECISION and RANGE). Atleastone ofthe scalarintegers P and R must be present.–1isreturnedifthe precisionis unavailable, –ifthe range is unavailable, and –if neither are available.
C.13. Transfer Function TRANSFER(SOURCE, MOLD [,SIZE]: same physicalrepresentation as SOURCE, but type of MOLD. Scalarif MOLD isscalar,otherwise ofrank one and sizejustsufficientto hold allof SOURCE. If SIZE is present,resultis ofrank one and size SIZE.
C.14. Non-elemental Intrinsic Subroutines See Random numbers and Real-time clock.
Random numbers Pseudo-random numbers are generated from a seed held as a rank-one integer array. RANDOM_NUMBER returns the random numbers, and RANDOM_SEED allows inquiries about the seed array, and the seed to be reset.
0 ≤ x < 1, or an array ofsuch numbers,in HARVEST, which has intent OUT and must be real.
CALL RANDOM_NUMBER(HARVEST): random number x uniformly distributed in the range
CALL RANDOM_SEED([SIZE] [,PUT] [,GET]) :
•
•
•
SIZE (scalarinteger) hasintent OUT and isset by the system to the size N ofthe seed array; PUT (rank-one integer array size N) has intent IN and is used by the system to resetthe seed; GET (rank-oneinteger array size N) hasintent OUT and is set by the system tothe current value of the seed.
Not more than one argument may be specified; if none is specified, the seed is set to a systemdependent value. See Chapter14 for examples.
Real-time clock CALL DATE_AND_TIME([DATE] [,TIME] [,ZONE] [,VALUES]): returns (values are blank or -HUGE(0) ifthere is no clock) •
•
• •
272
DATE (character) as ccyymmdd (century —day); TIME (character) as hhmmss.sss (hours— milliseconds); ZONE (character) as Shhmm (difference between local and Co-ordinated Universal Time — UTC — S isthe sign); VALUES (rank-oneinteger array) holdingthe year, month,day,time differencein minutes with respectto UTC,hour, minutes,seconds, and milliseconds.
CALL SYSTEM_CLOCK([COUNT] [,COUNT_RATE] [,COUNT_MAX]): returns •
•
•
COUNT (integer) holding current value of system clock; COUNT_RATE (integer) holding number of clock counts per second; COUNT_MAX (integer) holding maximum value /COUNT/ may take.
Appendix D ASCII Character Codes The ASCII (American Standard Code for Information Interchange) collating sequence is as follows:
273
Appendix E Solutions to Selected Exercises Solutions to the exercises are listed in each Chapter topic.
Chapter 1 1.1
1.2
PROGRAM Arith REAL A, B PRINT*, "Enter A and B:" READ*, A, B PRINT*, "Sum: ", A PRINT*, "Difference:", A PRINT*, "Product: ", A PRINT*, "Quotient: ", A END PROGRAM Arith
+ * /
B B B B
PROGRAM Energy REAL C, E, V READ*, C, V E = C * V ** 2 / 2 PRINT*, "Stored energy:", E END PROGRAM Energy
Chapter 2 2.2 (a) comma should be replaced by decimal point (e) asterisk should be omitted (f) exponent must be integer (h) comma should be replaced by decimal point 2.3 (b) decimal point not allowed (c) first character must be aletter (d) apostrophes not allowed (f) first character must be aletter (h) blanks not allowed (i) decimal points not allowed (k) asterisk not allowed (l) allowed but notrecommended! 2.4 (a) (b) (c) (d) (e) (f) 2.5 (a) (b) (c) (d) (e) (f) (g)
274
REAL, PARAMETER :: Pi = 3.1415927 PRINT*, 2 ** (0.5) PRINT*, (5. + 3) / (5 * 3) ! real division PRINT*, (2.3 * 4.5) ** (1.0/3) ! real division in exponent PRINT*, (2 * Pi) ** 2 PRINT*, 2 * Pi ** 2 PRINT*, 1000 * (1 + 0.15/12) ** 60 P + W / U P + W / (U + V) (P + W / (U + V)) / (P + W / (U - V)) X ** (1 / 2.0) Y ** (Y + Z) X ** Y ** Z (X ** Y) ** Z ! ** goes from right to left by default
(h) X - X ** 3 / (2.*3) + X ** 5 / (2.*3*4*5) 2.6
I = 2 ** 30 - 1 + 2 ** 30
2.7
REAL A, B, C, X READ*, A, B, C X = (-B + (B ** 2 - 4 * A * C) ** (0.5)) / (2.0 * A) PRINT*, X END
2.8
REAL G, P, L PRINT*, "Enter gallons and pints:" READ*, G, P P = 8 * G + P L = P / 1.76 PRINT*, L, "litres" END
2.9
IMPLICIT NONE REAL Km, L, Km_L, L_100Km Km = 528 L = 46.23 Km_L = Km / L L_100Km = L / (Km / 100) PRINT*, " Distance", " Litres used", " Km/L", " L/100Km" PRINT* PRINT*, Km, L, Km_l, L_100Km END
2.10
T = A A = B B = T
2.11
A = A - B B = B + A A = B - A
2.13
REAL L, P, R INTEGER N L = 50000 PRINT*, "Enter N READ*, N, R P = R * L * (1 + P = P / 12 / ((1 PRINT*, "Monthly END
and R (as a decimal):" R/12) ** (12*N) + R/12) ** (12*N) - 1) payment:", P
2.14
REAL L, N, R, P PRINT*, "Capital amount, monthly payment, interest rate" READ*, L, P, R N = LOG( P / (P - R*L/12) ) N = N / 12 / LOG( 1 + R/12 ) PRINT*, "Repayment period in years/months:", N, 12 * N END
2.15
REAL, PARAMETER :: Pi = REAL C, E, I, I1, L, R, R = 5; C = 10; L = 4; E I1 = 2 * Pi * Omega * L I = E / (R ** 2 + I1 ** PRINT*, "Current:", I END
3.1415927 Omega = 2; Omega = 2 - 1 / (2 * Pi * Omega * C) 2) ** 0.5
275
Chapter 3 3.1 (a) I = I + 1 (b) I = I ** 3 + J (c) IF (E > F) THEN G = E ELSE G = F END IF (d) IF (D > 0) X = -B (e) X = (A + B) / (C * D) 3.2
REAL F INTEGER C DO C = 20, 30 F = 9 * C / 5 + 32 PRINT*, C, F END DO
3.3
INTEGER I DO I = 10, 20 PRINT*, I, SQRT(1. * I) ! SQRT may not have an integer argument END DO
3.5
INTEGER I, SUM SUM = 0 DO I = 1, 100 SUM = SUM + 2 * I END DO
3.7
INTEGER I, N, NumPass REAL Avg, Mark NumPass = 0 Avg = 0 N = 10 OPEN( 1, FILE = "Marks" ) DO I = 1, N READ (1, *) Mark Avg = Avg + Mark IF (Mark >= 5) NumPass = NumPass + 1 END DO Avg = Avg / N PRINT*, "Average:", Avg PRINT*, NumPass, "passed"
3.9,
A = 4, X = 1 + 1/2 + 1/3 + 1/4.
3.10
X = 0 DO K = 1, 4 X = X + 1 / K END DO
3.11
The limit is pi.
3.13
REAL Bal, Dep, Intr, Rate INTEGER Mon Bal = 0 Dep = 50 Rate = 0.01
276
PRINT*, "Month", " Balance" DO Mon = 1, 12 Bal = Bal + Dep Intr = Rate * Bal Bal = Bal + Intr PRINT*, Mon, " ", Bal END DO END 3.16
REAL A, B, K, P INTEGER T K = 197273000 A = 0.03134 B = 1913.25 PRINT "(A5, A20)", "Year", "USA Population" DO T = 1790, 2000, 10 P = K / (1 + EXP( -A * (T - B) )) PRINT "(I5, F20.0)", T, P END DO END
3.18
INTEGER Feet, Yards REAL Inches, Metres READ*, Metres Inches = 39.37 * Metres Yards = Inches / 36 Inches = MOD( Inches, 36.0 ) ! inches left Feet = Inches / 12 Inches = MOD( Inches, 12.0 ) PRINT*, "Imperial:", Yards, Feet, Inches
3.19 (a) C = SQRT(A * A + B * B) ! * is quicker than ** (b) Theta = Theta * Pi / 180 ! convert to radians C = SQRT(A * A + B * B - 2 * A * B * Cos(Theta)) 3.20 (a) (b) (c) (d) (e)
Y = LOG(X + X * X + A * A) Y = (EXP(3 * T) + T * T * SIN(4 * T)) * COS(3 * T) ** 2 Pi = 4 * ATAN(1.0) Y = 1 / COS(X) ** 2 + 1 / TAN(Y) Y = ATAN( ABS(A/X) )
Chapter 4 4.1 You should get a picture of tangentsto a curve. 4.2 (a), 4,,(b),2 (c) The algorithm (attributed to Euclid) finds the HCF (Highest Com mon Factor) of two numbers by usingthefactthatthe HCF divides exactlyinto the difference betweenthetwo numbers, and thatifthe numbers are equal,they are equaltotheir HCF. 4.3
REAL C, F READ*, F C = (F - 32) * 5.0 / 9 PRINT*, "Celsius:", C
4.5
REAL A, B READ*, A, B IF (A > B) THEN PRINT*, A, "is greater" ELSE PRINT*, B, "is greater" END IF
277
4.6
REAL X, MaxX INTEGER I, MaxPos OPEN( 1, FILE = "MARKS" ) MAxX = -HUGE(0) ! smallest (most negative) number DO I = 1, 10 READ (1, *) X IF (X > MaxX) THEN ! X is biggest so far MaxX = X MaxPos = I ! record position END IF END DO PRINT*, MaxX, "in position", MaxPos
4.7
REAL :: Sum = 0 ! initialization INTEGER N DO N = 1, 100 Sum = Sum + 1.0 / N ! remember integer division IF (MOD( N, 10 ) == 0) PRINT*, Sum END DO
4.8
INTEGER Secs, Mins, Hours READ*, Secs Hours = Secs / 3600 Secs = MOD( Secs, 3600 ) ! number of seconds over Mins = Secs / 60 Secs = MOD( Secs, 60 ) PRINT*, Hours, ":", Mins, ":", Secs
Chapter 5 5.1
REAL A, B READ*, A, B IF (A > B) THEN PRINT*, A, "is larger" ELSE IF (B > A) THEN PRINT*, B, "is larger" ELSE PRINT*, "number are equal" END IF
5.2 1. Repeat
10 Read If
number < increase negative otherwise if number increase zero otherwise increase positive counter 2. Print counters. INTEGER I, Num, NPos, NZer, NNeg NPos = 0; NZer = 0; NNeg = 0; DO I = 1, 10 READ*, Num SELECT CASE (Num) CASE (:-1) NNeg = NNeg + 1 CASE (0) NZer = NZer + 1
278
0 =
0
times: number then counter then counter
CASE DEFAULT NPos = NPos + 1 END SELECT END DO PRINT*, NNeg, NZer, NPos 5.5 1. Read a, b, c, d, e, f 2. u = ae - db,: v = ec - bf 3. If u Lines Otherwise if Lines Otherwise x = Print x, y 4. Stop.
= u
0 =
v
and 0
= v
and
0 ≠
0
are v/u,
:
y
=
then coincide then parallel (af-dc)/u
REAL A, B, C, D, E, F, U, V, X, Y READ*, A, B, C, D, E, F U = A * E - D * B V = E * C - B * F IF (U == 0 .AND. V == 0) THEN PRINT*, "Lines coincide" ELSE IF (U == 0 .AND. V /= 0) THEN PRINT*, "Lines parallel" ELSE X = V / U Y = (A * F - D * C) / U PRINT*, "x, y:", X, Y END IF
Chapter 6 6.2
INTEGER X REAL Ang, Pi Pi = 4 * ATAN(1.0) DO X = 0, 90, 15 Ang = X * Pi / 180 ! convert to radians PRINT "(I3, 2F7.4)", X, SIN(Ang), COS(Ang) END DO
6.3
REAL Bal, Rate INTEGER Month, Year Bal = 1000 Rate = 0.01 DO Year = 1, 10 DO Month = 1, 12 Bal = (1 + Rate) * Bal END DO PRINT*, Year, Bal END DO
6.4 (a) REAL Pi INTEGER K, N, Sign Pi = 1 Sign = 1 PRINT*, "Number of terms?" READ*, N DO K = 1, N
279
Sign = -Sign Pi = Pi + Sign / (2 * K + 1.0) ! avoids integer division END DO Pi = 4 * Pi 6.4 (b) REAL :: Pi = 0 INTEGER K, N PRINT*, "Number of terms?" READ*, N DO K = 1, N Pi = Pi + 1.0 / (4 * K - 3) / (4 * K - 1) ! avoids integer division END DO Pi = 8 * Pi 6.7
REAL(2) E, X ! greatest precision X = 0.1 DO I = 1, 20 E = 1.0 / (1 - X) ** (1/X) PRINT*, X, E X = X / 10 END DO
6.8
REAL, PARAMETER :: Pi = 3.1415927 REAL Fourier, T INTEGER K, N PRINT*, "N:" READ*, N T = 0 DO WHILE (T = 100) EXIT Ans = Sum ! since Sum will go over 100 NumTerms = I I = I + 1 Sum = Sum + I END DO PRINT*, Ans, "after", NumTerms, "terms"
6.12
INTEGER M, N READ*, M, N DO WHILE (M /= N) DO WHILE (M > N) M = M - N END DO DO WHILE (N > M) N = N - M END DO END DO PRINT*, "HCF is", M
280
6.14 The finalpaymentis $157.75 in the 54th month (don'tforgetthe interestinthe lastmonth).
Chapter 8 8.2
REAL X READ*, X PRINT*, X, Expo(X), EXP(X) CONTAINS FUNCTION Expo( X ) REAL Expo, Term REAL, INTENT(IN) :: X INTEGER K Expo = 1 K = 1 Term = 1 DO WHILE (ABS(Term) >= 1e-6) Term = Term * X / K Expo = Expo + Term K = K + 1 END DO END FUNCTION Expo END
8.5
FUNCTION Normal( X ) REAL Normal, R, T REAL, INTENT(IN) :: X REAL :: A = 0.4361836 REAL :: B = -0.1201676 REAL :: C = 0.937298 REAL :: Pi = 3.1415927 R = EXP( -X * X / 2 ) / SQRT(2 * PI) T = 1 / (1 + 0.3326 * X) Normal = 0.5 - R * (A * T + B * T * T + C * T ** 3) END FUNCTION Normal
8.6
INTEGER N DO N = 1, 20 PRINT "(I4, F9.1)", N, Fibo(N) END DO CONTAINS RECURSIVE FUNCTION Fibo( N ) RESULT (F) REAL F INTEGER N IF (N == 0 .OR. N == 1) THEN F = 1 ELSE F = Fibo(N-1) + Fibo(N-2) END IF END FUNCTION Fibo END
Chapter 9 9.1
INTEGER, DIMENSION(100) :: Num (a) Num = (/ (I, I = 1, 100) /) (b) DO I = 1, 50 Num(I) = 2 * I END DO (c) DO I = 1, 100 ! or Num = (/ (I, I = 100, 1, -1) /) Num(101-I) = I
281
END DO 9.2
REAL F(100), F1, F2 READ*, F(1), F(2) DO N = 3, 100 F(N) = F(N-1) + F(N-2) END DO
9.3
REAL :: S(7) = (/ 9, 10, 12, 15, 20, 35, 50 /) INTEGER :: Emps(7) = (/ 3000, 2500, 1500, 1000, 400, & 100, 25 /) INTEGER :: NumScales = 7 INTEGER I, Above, Below REAL AvLevel, AvSal Above = 0; Below = 0 AvLevel = SUM( S ) / NumScales ! intrinsic SUM DO I = 1, NumScales IF (S(I) < AvLevel) THEN Below = Below + Emps(I) ELSE Above = Above + Emps(I) END IF END DO AvSal = 1000 * SUM( S ) / SUM( Emps ) ! intrinsic SUM
9.4
INTEGER X(10), Num, I REAL Mean, Dist READ*, X Mean = SUM( X ) / 10 ! intrinsic SUM Dist = ABS(X(1) - Mean) ! it may be the first one Num = X(1) DO I = 2, 10 IF (ABS(X(I) - Mean) > Dist) THEN Num = X(I) ! furthest number Dist = ABS(X(I) - Mean) ! distance from mean END IF END DO
9.5 1. Initialize: N = 3,: P1 = 2, j = 1 (prime counter) 2. W hile N < i R
=
W hile
R Increase
≠
R Increase
P1 = N
Increase N by 2 3. Print allthe 4. Stop.
Pj
's
Chapter 10 10.3
282
N,
M O D( 0
CHARACTER (1) :: ch = "" INTEGER :: NonBlank = 0
and i
R If
1000
j
repeat: 1
=
= ≠ by
P1 )
P1 < by 0
1
(that's
(remainder)
N
repeat: 1
M O D ( N , P1 ) then another prime)
INTEGER :: IOEnd = 0 OPEN( 1, FILE = 'TEST' ) DO WHILE (IOEnd /= -1) ! for EOF under FTN90 READ (1, "(A1)", IOSTAT = IOEnd, ADVANCE = "NO") ch IF (ch /= ' ') NonBlank = NonBlank + 1 END DO PRINT*, NonBlank CLOSE (1)
Chapter 11 11.1
CHARACTER(80) Line INTEGER :: Blanks = 0 INTEGER I READ*, Line ! use quotes if text contains blanks DO I = 1, LEN_TRIM( Line ) IF (Line(I:I) == " ") Blanks = Blanks + 1 END DO
11.2
INTEGER I, PosStop CHARACTER(80) Sentence READ*, Sentence ! enclose in quotes if blanks in text PRINT*, Sentence PosStop = INDEX( Sentence, "." ) PRINT*, PosStop DO I = PosStop-1, 1, -1 WRITE (*, "(A1)", ADVANCE = "NO") Sentence( I:I ) END DO
11.3
PROGRAM Zeller CHARACTER (9), DIMENSION(0:6) :: DayOfWeek = & (/ "Sunday ", "Monday ", "Tuesday ", & "Wednesday", "Thursday ", "Friday ", "Saturday " /) INTEGER Centy, Day, Month, Year, F PRINT*, "Enter day, month, year:" READ*, Day, Month, Year Month = Month - 2 IF (Month = 11) Year = Year - 1 Centy = Year / 100 Year = MOD( Year, 100 ) ! year in century now F = INT(2.6 * Month - 0.2) + Day + Year + Year / 4 & + Centy / 4 - 2 * Centy F = MOD( F, 7 ) PRINT*, DayOfWeek(F) END
11.4
PROGRAM BinToDec CHARACTER(80) StrBin ! maximum length is 80 INTEGER, ALLOCATABLE :: Bin(:) INTEGER Dec, I, N READ*, StrBin N = LEN_TRIM( StrBin ) ! number of binary digits ALLOCATE( Bin(N) ) READ (StrBin, "(80I1)") Bin ! reads first N digits Dec = 0 DO I = 1, N Dec = Dec + Bin(I) * 2 ** (N-I) END DO PRINT*, Dec END
283
11.5
PROGRAM Upper CHARACTER (1) :: ch INTEGER :: IOEnd = 0 OPEN( 1, FILE = "TEXT" ) DO WHILE (IOEnd /= -1) ! for EOF under FTN90 READ (1, "(A1)", IOSTAT = IOEnd, ADVANCE = "NO") ch IF (ch >= "a" .AND. ch I P2 => J PRINT*, P1, P2 Temp => P1 P1 => P2 P2 => Temp PRINT*, P1, P2 ! check where they point now
Chapter 14 14.1
PROGRAM Bingo INTEGER Bing(99), I, Temp, Seed(1), Count, R REAL Rnd CALL SYSTEM_CLOCK( Count ) Seed = Count CALL RANDOM_SEED( PUT = Seed ) Bing = (/ (I, I = 1, 99) /) DO I = 1, 99 CALL RANDOM_NUMBER(Rnd) R = INT( 99 * Rnd + 1 ) Temp = Bing(R) Bing(R) = Bing(I) Bing(I) = Temp END DO PRINT "(10I3)", Bing END
14.2
PROGRAM Walk INTEGER, PARAMETER :: Xmax = 20 INTEGER X, F(-Xmax:Xmax), I, N REAL R
284
X = 0 F = 0 READ*, N DO I = 1, N CALL RANDOM_NUMBER(R) IF (R < 0.5) THEN X = X + 1 ELSE X = X - 1 END IF F(X) = F(X) + 1 ! that's another one at X END DO DO X = -Xmax, Xmax PRINT "(80A1)", ("*", I = 1, F(X)) END DO END 14.3
PROGRAM MonteCarlo REAL R, X, Y, Pi INTEGER I, N Pi = 0 READ*, N DO I = 1, N CALL RANDOM_NUMBER(R) X = -1 + 2 * R Y = -1 + 2 * R IF (X*X + Y*Y < 1) Pi = Pi + 1 END DO Pi = 4 * Pi / N PRINT*, "Pi is very roughly", Pi END
! -1 to 1 ! ditto
14.5 Theoretically(from the binomial distribution),the probability of a DFII crashing is 1/4, while that of a DFIV crashing is 5/16; more can go wrong with itsince it has more engines! 14.6 On average, A wins 12 ofthe possible 32 plays ofthe game, while B wins 20, as can be seen from drawing the game tree. Your simulation should come up with these proportions.(However,it can be shown from the tree that B can always force a win,if she plays intelligently.)
Chapter 15 15.1
SUBROUTINE MyTrans( A ) REAL, DIMENSION(:,:) :: A INTEGER J, K REAL Temp DO J = 1, SIZE(A,1) DO K = J, SIZE(A,1) ! start at J to avoid swopping back Temp = A(J,K) A(J,K) = A(K,J) A(K,J) = Temp END DO END DO END SUBROUTINE MyTrans
Chapter 16 16.1 (a) The realroots are 1.856 and –.697,the complex roots are 0.0791±1.780i.
(b) 0.589, 3.096, 6.285,...(roots get closerto multiples of π). (c) 1, 2, 5. (d) 1.303(e) Real roots at 1.768 and 2.241.
285
16.2 Successive bisections are: 1.5, 1.25, 1.375, 1.4375 and 1.40625. The exact answer is 1.414214...,so the last bisection is within the required error. 16.3 22 (exact answer is 21.3333). rt
16.4 After 30 yearsthe exact answer is 2117 (1000e ) . 16.5 The differential equations to be solved are
dS / dt = − r1 S dY / dt = r1 S − r2 Y The exact solution after 8 hoursis S = 6.450 × 1025 and Y = 2.312 × 1026 16.6
PROGRAM IMPALA INTEGER I, N REAL A, B, H, R, T, X PRINT*, "Enter R, B, A, X(0), H:" READ*, R, B, A, X, H N = INT( 24/H + SPACING(H) ) + 1 ! trip count T = 0 DO I = 1, N IF (MOD(I-1, INT(1/H + SPACING(H))) == 0) THEN ! output ! every month starting with initial value PRINT "(2F8.2)", T, X END IF T = T + H X = X + H * (R - B * X * SIN(A * T)) * X END DO END
16.7 With 10 intervals (n = 5), the luminous efficiency is 14.512725%. With 20 intervals it is 14.512667%. These resultsjustifythe use of 10 intervalsin any further computationsinvolving this problem. This isa standard way oftestingthe accuracy of a numerical method: halvethe step-length and see how much the solution changes.
286