-
-
Notifications
You must be signed in to change notification settings - Fork 6
initial proposed changes to Ep2 - Basics #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6402f32
d7c4024
3744b87
900449f
fcb2bf3
e20bcb7
abdb0ab
0af6e5c
bef7877
826f669
eabc28b
2e2cf0b
80b7006
c2a2b9d
43efde7
cb8301e
67ae508
e92d238
0539a7f
a142006
92d0685
8940443
36c7a98
e285d81
da2c2dd
f9385d8
604db39
6e64c87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,343 @@ | ||
| --- | ||
| title: 'Basics' | ||
| teaching: 35 | ||
| exercises: 15 | ||
| --- | ||
|
|
||
| ::::::::::::::::::::::::::::::::::::: questions | ||
|
|
||
| - How do we represent and manipulate data in Fortran? | ||
|
|
||
| :::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
|
||
| ::::::::::::::::::::::::::::::::::::: objectives | ||
|
|
||
| - Understand the different intrinsic data types | ||
| - Understand the different intrinsic operators and functions available | ||
|
|
||
| :::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
|
||
| ## Fortran data types | ||
|
|
||
| Fortran provides the following intrinsic data types: | ||
|
|
||
| * numeric types | ||
| * `integer` | ||
| * `real` | ||
| * `complex` | ||
| * non-numeric types | ||
| * `logical` | ||
| * `character` | ||
|
|
||
| ### Defining numeric variables | ||
|
|
||
| The following program declares a variable with each of the three intrinsic | ||
| numeric types, and provides an initial value in each case. | ||
| ```fortran | ||
| program example1 | ||
|
|
||
| integer :: i = 1 ! An integer | ||
| real :: a = 2.0 ! A floating point number | ||
| complex :: z = (0.0, 1.0) ! A complex number as (real-part, imag-part) | ||
|
|
||
| end program example1 | ||
| ``` | ||
| Initial values are optional, and these values may be changed later within the code. | ||
| If a declaration does not specify an initial value, the variable is said to be _undefined_. | ||
|
|
||
| ### Variable names | ||
|
|
||
| The valid Fortran character set for names is `a-z`, `A-Z`, `0-9` and the | ||
| underscore `_`. Valid names must begin with a character. The maximum | ||
| length of a name is 63 characters (introduced in the F2003 standard) with | ||
| no spaces allowed. This includes names for programs, modules, subroutines, | ||
| and functions, as well as names for variables. | ||
|
|
||
| ### The `implicit` statement | ||
|
|
||
| By default, variables in Fortran do not need to be declared a specific type, they | ||
| can just be used within the code. Variables with names beginning with letters `i-n` are implicitly | ||
| of type `integer`, while anything else is of type `real` (unless explicitly declared otherwise). | ||
|
|
||
| **This is very bad practice and modern Fortran should not be used in this way.** | ||
|
|
||
| The solution to prevent errors involving undeclared variables (usually arising from | ||
| typos) is to declare that no names have implicit type via the use of the | ||
| ```fortran | ||
| implicit none | ||
| ``` | ||
| statment at the very top of the code. | ||
|
|
||
| With this statement inserted, all variable names must be declared explicitly before they | ||
| are referenced. It is still common to see variables beginning with `i-n` as integers. | ||
|
|
||
| ::::::::::::::::::::::::::::::::::::: challenge | ||
|
|
||
| ## Use `implicit none` | ||
|
|
||
| Edit the above example to include an `implicit none` statment, and print out the three variables | ||
|
|
||
| :::::::::::::::: solution | ||
|
|
||
| ```fortran | ||
| program solution1 | ||
| implicit none | ||
|
|
||
| integer :: i = 1 ! An integer | ||
| real :: a = 2.0 ! A floating point number | ||
| complex :: z = (0.0, 1.0) ! A complex number as (real-part, imag-part) | ||
|
|
||
| print *, i, a, z | ||
|
|
||
| end program solution1 | ||
| ``` | ||
| Compiling and running this code will give the following output | ||
| ``` | ||
| $ ./a.out | ||
| 1 2.00000000 (0.00000000,1.00000000) | ||
| ``` | ||
|
|
||
| ::::::::::::::::::::::::: | ||
| ::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
|
||
| ### Parameters | ||
|
|
||
| In the above example, it is possible to change the values of initialised variables, e.g. | ||
| ```fortran | ||
| program example2 | ||
| implicit none | ||
|
|
||
| real :: a = 2.0 | ||
|
|
||
| print *, a | ||
|
|
||
| a = a + 5.0 | ||
|
|
||
| print *, a | ||
|
|
||
| end program example2 | ||
| ``` | ||
| This will then give the output: | ||
| ``` | ||
| $ ./a.out | ||
| 2.00000000 | ||
| 7.00000000 | ||
| ``` | ||
| However, you can also define constant values that cannot change by defining variables using `parameter`. | ||
| We are then unable to modify `parameter` variables, e.g. | ||
| ```fortran | ||
| program example3 | ||
| implicit none | ||
|
|
||
| real, parameter :: pi = 3.14159265 | ||
|
|
||
| pi = pi + 2.0 | ||
|
|
||
| print *, pi | ||
|
|
||
| end program example3 | ||
| ``` | ||
| When compiling this program, this will give an error similar to the following from the `gfortran` compiler: | ||
| ``` | ||
| example3.f90:6:3: | ||
|
|
||
| 6 | pi = pi + 2.0 | ||
| | 1 | ||
| Error: Named constant 'pi' in variable definition context (assignment) at (1) | ||
| ``` | ||
|
|
||
| ::::::::::::::::::::::::::::::::::::: challenge | ||
|
|
||
| ## Write a Fortran program to calculate the circumference of a circle | ||
|
|
||
| Using the `parameter` statement, write a Fortran program to calculate the circumference of a circle of | ||
| radius 3.0. | ||
|
|
||
| ::::::::::::::::: hint | ||
|
|
||
| The cicumference $c$ of a circle can be calculated from the radius $r$ and constant $\pi$ by | ||
|
|
||
| $c = 2 \pi r$ | ||
|
|
||
| :::::::::::::::::::::: | ||
|
|
||
| :::::::::::::::: solution | ||
|
|
||
| ```fortran | ||
| program solution2 | ||
| implicit none | ||
|
|
||
| real, parameter :: pi = 3.14159265 | ||
|
|
||
| real :: r=3.0 ! radius of the circle | ||
| real :: c ! circumference of the circle | ||
|
|
||
| c = 2.0 * pi * r | ||
|
|
||
| print *, c | ||
|
|
||
| end program solution2 | ||
| ``` | ||
| Compiling and running this code will give the following output | ||
| ``` | ||
| $ ./a.out | ||
| 18.8495560 | ||
| ``` | ||
|
|
||
| ::::::::::::::::::::::::: | ||
| ::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
|
||
| ## Logical variables | ||
|
|
||
| Fortran has a `logical` type that has two literal values, True and False, defined by | ||
| ```fortran | ||
| logical :: switch0 = .false. | ||
| logical :: switch1 = .true. | ||
| ``` | ||
|
|
||
| ### Logical operators and expressions | ||
|
|
||
| Values can be tested logical operators `.or.`, `.and.` and `.not.` are available, and | ||
| these can be used to set the value of logical variables. | ||
|
|
||
| The precedence is illustrated by, e.g., | ||
| ```fortran | ||
| q = i .or. j .and. .not. k ! evaluated as i .or. (j .and. (.not. k)) | ||
| ``` | ||
| where q, i, j, and k are all logical variables. | ||
|
|
||
| The use of parentheses is highly recommended to avoid ambiguity and/or to add clarity. | ||
|
|
||
| ### Relational operators | ||
|
|
||
| To form logical expressions from numeric or other expressions, we require | ||
| relational operators. The are two forms in Fortran, illustrated in the table | ||
| below. It is recommended that you avoid the older form. | ||
|
|
||
| | Relation | Operator | Older form | For | | ||
| |--------------------------|----------|------------|------------------| | ||
| | Less than | `< ` | `.lt.` | `integer` `real` | | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. put commas in these lists in table |
||
| | Less than or equal to | `<=` | `.le.` | `integer` `real` | | ||
| | Greater than | `> ` | `.gt.` | `integer` `real` | | ||
| | Greater than or equal to | `>=` | `.ge.` | `integer` `real` | | ||
| | Equal to | `==` | `.eq.` | `integer` `real` `complex`| | ||
| | Not equal to | `/=` | `.neq.` | `integer` `real` `complex`| | ||
|
|
||
| ### Logical equivalence | ||
|
|
||
| Equivalence between two logical expressions or variables is established | ||
| via the logical operators `.eqv.` and `.neqv.`. | ||
|
|
||
| While some some compilers may allow the use of `==`, this should be avoided. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| ### Using logical operators | ||
|
|
||
| These operators can be used to check and set the values of logical variables, dependent on other variables, e.g. | ||
| ```fortran | ||
| program example4 | ||
| implicit none | ||
|
|
||
| real, parameter :: pi = 3.14159265 | ||
| logical, parameter :: switch1 = .true. | ||
|
|
||
| real :: a=3.0 | ||
| logical :: test1, test2, test3 | ||
|
|
||
| test1 = a >= pi ! True if a is greater than or equal to pi | ||
|
|
||
| test2 = (.not. test1) ! True if test1 is False, False if test1 is True | ||
|
|
||
| test3 = (test2 .eqv. switch1) ! True if test2 is True, False if test2 is False | ||
|
|
||
| print *, test1 | ||
|
|
||
| print *, test2 | ||
|
|
||
| print *, test3 | ||
|
|
||
| end program example4 | ||
| ``` | ||
| Compiling and running this code will give the following output | ||
| ``` | ||
| $ ./a.out | ||
| F | ||
| T | ||
| T | ||
| ``` | ||
|
|
||
| ## Character variables | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Draft content to be moved to file 05-strings ? |
||
|
|
||
| Character variables are strings that hold zero or more characters. Some examples are: | ||
| ```fortran | ||
| program example5 | ||
| implicit none | ||
|
|
||
| character (len = *), parameter :: string1 = "don't" ! assumed length of 5 characters | ||
| character (len = 5) :: string2 = "Don""t" ! 5 characters | ||
| character (len = 6) :: string3 = ' don''t' ! blank + 5 characters | ||
|
|
||
| end program example5 | ||
| ``` | ||
| There should be a `len` specifier. Specifying `len = *` means that the length will be assumed | ||
| from the length of the string. A space is a valid character in a string. | ||
|
|
||
| Strings must be defined within quotation marks, either single, `'`, or double, `"`, beginning | ||
| and ending with the same type of mark. To define a quotation mark within a string, either | ||
| use one of the alternative type, e.g. `"'"`, or use two of the same type, e.g. `''''`, which | ||
| will be intepreted as a single mark within the string. | ||
|
|
||
| Strings may be concatenated with the string concatenation operator `//`. For example `string2` | ||
| and `string3` could be concatenated into a new variable `string4` by | ||
| ```fortran | ||
| string4 = string2//string3 | ||
| ``` | ||
| A single character, or a subset of characters, can be extracted via | ||
| use of an array-index like notation by defining the start and end characters | ||
| to extract, e.g. `string1(1:1)` would extract only the first character from the string | ||
| variable `string1`. | ||
|
|
||
| ::::::::::::::::::::::::::::::::::::: challenge | ||
|
|
||
| ## Working with strings | ||
|
|
||
| Using the above `example5`, concatenate `string2` and `string3` into a new variable `string4`, | ||
| and print out the values of all strings. Also, print the third character of `string4`. | ||
|
|
||
| :::::::::::::::: solution | ||
|
|
||
| ```fortran | ||
| program solution3 | ||
| implicit none | ||
|
|
||
| character (len = *), parameter :: string1 = "don't" ! 5 characters | ||
| character (len = 5) :: string2 = "Don""t" ! 5 characters | ||
| character (len = 6) :: string3 = ' don''t' ! blank + 5 characters | ||
| character (len = 11) :: string4 ! length of string2+string3 | ||
|
|
||
| string4 = string2//string3 | ||
|
|
||
| print *, string1 | ||
|
|
||
| print *, string2 | ||
|
|
||
| print *, string3 | ||
|
|
||
| print *, string4 | ||
|
|
||
| print *, string4(3:3) | ||
|
|
||
| end program solution3 | ||
| ``` | ||
| Compiling and running this code will give the following output | ||
| ``` | ||
| $ ./a.out | ||
| don't | ||
| Don"t | ||
| don't | ||
| Don"t don't | ||
| n | ||
| ``` | ||
|
|
||
| ::::::::::::::::::::::::: | ||
| ::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone might think this doesn't work because of the use of itself in calculating its new value, an example like
pi = 3.0may be clearer