From f8a6148ac729f940a186a6629a1efa4c7cb8bd8a Mon Sep 17 00:00:00 2001
From: rasmus
Not bad huh? The things you see when everyone is asleep.
And this is my humble bike. It has taken me many places, and it's still going strong. The odometer no longer works, so I just use my FitBit Charge 5 instead. I've modeled and 3D printed the two orange bottle holders myself, on my Original Prusa MK3S+.
diff --git a/src/components/Fortran/Fortran_Data_Types.vue b/src/components/Fortran/Fortran_Data_Types.vue new file mode 100644 index 0000000..5be33dc --- /dev/null +++ b/src/components/Fortran/Fortran_Data_Types.vue @@ -0,0 +1,425 @@ + + + +Just like any other programming language that has datatypes, Fortran has datatypes as well. The big difference, from
+ other languages, of cause, is how they're created and assigned. If you're a developer of, for example, C#, Java or
+ even Python, you will feel the difference pretty fast.
+
+ Let's look at a small list of some common types.
+
integer
real
double precision
logical
character
integer
is, if you hadn't guessed, a whole number. Like most languages,
+ int
. The real
type is like a
+ float
. But the difference with Fortran types, in general, is that you have "less" types,
+ but you have more control over those types, making it essentially the same as if you had more types. More on that later.
+
+ The double precision
is a double, obviously. And as you have probably guessed at
+ this point, logical
is a boolean. character
+ however, is a little bit different. In "new" programming terms, it would be an array of characters that behaves
+ like a string. Or like in SQL: VARCHAR(256)
.
In Fortran, you can specify the size of an integer at declaration. You do that with (kind = n)
.
+ So if you want a 16 bit integer, you do integer(kind = 16)
. Observe the following code example.
+ As an exercise for the reader, try to imagine what would be printed to the terminal.
+
+ *Do note that we're using Fortran 90, and not the newer versions that supports unsigned integers.[1]
+
+program hello
+ implicit none
+
+ integer :: int1;
+ integer(kind = 2) :: int2;
+ integer(kind = 4) :: int4;
+ integer(kind = 8) :: int8;
+ integer(kind = 16) :: int16;
+
+ print *, 'int'
+ print *, huge(int1)
+ print *
+ print *, 'kind = 2'
+ print *, huge(int2)
+ print *
+ print *, 'kind = 4'
+ print *, huge(int4)
+ print *
+ print *, 'kind = 8'
+ print *, huge(int8)
+ print *
+ print *, 'kind = 16'
+ print *, huge(int16)
+
+end program hello
+
+ Now, as the astute reader might have already figured, the output would look like this:
+ +
+> gfortran main.f90
+> ./a.out
+ int
+ 2147483647
+
+ kind = 2
+ 32767
+
+ kind = 4
+ 2147483647
+
+ kind = 8
+ 9223372036854775807
+
+ kind = 16
+ 170141183460469231731687303715884105727
+
+ The
+
+ Any integer without a kind, is automatically a 4 byte integer. Integers with kind 2, is 2 bytes big. Integers with
+ kind 4 is 4 bytes big. And so on and so forth.
+
+ Usually, unless your working with huge datasets,
The
+program hello
+ implicit none
+
+ real :: real1;
+ real(kind = 4) real4;
+ real(kind = 8) real8;
+ real(kind = 16) real16;
+
+ print *, 'real'
+ print *, huge(real1)
+ print *, tiny(real1)
+ print *
+ print *, 'kind = 4'
+ print *, huge(real4)
+ print *, tiny(real4)
+ print *
+ print *, 'kind = 8'
+ print *, huge(real8)
+ print *, tiny(real8)
+ print *
+ print *, 'kind = 16'
+ print *, huge(real16)
+ print *, tiny(real16)
+
+end program hello
+
+ The output:
+ +
+> gfortran main.f90
+> ./a.out
+ real
+ 3.40282347E+38
+ 1.17549435E-38
+
+ real(kind = 4)
+ 3.40282347E+38
+ 1.17549435E-38
+
+ real(kind = 8)
+ 1.7976931348623157E+308
+ 2.2250738585072014E-308
+
+ real(kind = 16)
+ 1.18973149535723176508575932662800702E+4932
+ 3.36210314311209350626267781732175260E-4932
+
+ As you can see here, we have included a new print statement.
+program hello
+ implicit none
+
+ double precision :: double;
+
+ print *, 'real'
+ print *, huge(double)
+ print *, tiny(double)
+
+end program hello
+
+ And the output looks like this:
+ +
+> gfortran main.f90
+> ./a.out
+ real
+ 1.7976931348623157E+308
+ 2.2250738585072014E-308
+
+
+program hello
+ implicit none
+
+ logical :: bool;
+ logical(kind = 1) :: bool1;
+ logical(kind = 2) :: bool2;
+ logical(kind = 4) :: bool4;
+ logical(kind = 8) :: bool8;
+ logical(kind = 16) :: bool16;
+
+ print *, 'logical'
+ print *, 'value: ', bool
+ print *, 'size: ', sizeof(bool)
+ print *
+ print *, 'value: ', bool1
+ print *, 'size: ', sizeof(bool1)
+ print *
+ print *, 'value: ', bool2
+ print *, 'size: ', sizeof(bool2)
+ print *
+ print *, 'value: ', bool4
+ print *, 'size: ', sizeof(bool4)
+ print *
+ print *, 'value: ', bool8
+ print *, 'size: ', sizeof(bool8)
+ print *
+ print *, 'value: ', bool16
+ print *, 'size: ', sizeof(bool16)
+
+end program hello
+
+ Now I have a small exercise for the reader again. Let's assume that we are using
+> gfortran main.f90
+> ./a.out
+ logical
+ value: T
+ size: 4
+
+ value: T
+ size: 1
+
+ value: T
+ size: 2
+
+ value: T
+ size: 4
+
+ value: F
+ size: 8
+
+ value: T
+ size: 16
+
+ Huh, that was weird. The 8 bit logical is false, while the others are true. The reason for this behavior
+ could be a multitude of things. One could be optimization, as the compiler tries to make the program faster. And
+ by setting the 8 bit logical to false. It could also be how an unassigned logical is represented. For more information,
+ check the footnote number 2. [2]
+
+ A good programming practise is to always assign your logical when creating them.
+logical :: bool = .true.;
+logical(kind = 1) :: bool1 = .true.;
+logical(kind = 2) :: bool2 = .true.;
+logical(kind = 4) :: bool4 = .true.;
+logical(kind = 8) :: bool8 = .true.;
+logical(kind = 16) :: bool16 = .true.;
+
+ Now, the output looks as expected.
+ +
+> gfortran main.f90
+> ./a.out
+ logical
+ value: T
+ size: 4
+
+ value: T
+ size: 1
+
+ value: T
+ size: 2
+
+ value: T
+ size: 4
+
+ value: T
+ size: 8
+
+ value: T
+ size: 16
+
+
+
+ Observe the example below.
+program hello
+ implicit none
+
+ character :: char;
+ character(len = 10) :: char2 = 'a';
+
+ print *, 'character';
+ print *, 'value: ', char;
+ print *, 'size: ', sizeof(char);
+ print *
+ print *, 'value: ', char2;
+ print *, 'size: ', sizeof(char2);
+ print *
+ print *, 'value: ', char2//'lol';
+ print *, 'size: ', sizeof(char2);
+
+end program hello
+
+ Output looks like this:
+ +
+> gfortran main.f90
+> ./a.out
+ character
+ value: 4
+ size: 1
+
+ value: a
+ size: 10
+
+ value: a lol
+ size: 10
+
+ lol. With Fortran, if you create a character, with a certain size, but only assign it a smaller vallue,
+ the trailing indexes in the character will be filled with whitespace.
+
+ To mitigate this, we could either set the correct length when creating the character, or we could use the
+trim(char2)//'lol';
+
+ Now, the output should be fixed:
+ +
+> gfortran main.f90
+> ./a.out
+ character
+ value:
+ size: 1
+
+ value: a
+ size: 10
+
+ value: a lol
+ size: 10
+
+ with trim
+ value: alol
+ size: 10
+
+ Footnotes:
+ +A Hello World program is always a great step into a new programming language. It gives a simple oversight into +
A Hello World program is always a great step into a new programming language. It gives a simple oversight into the build process of said language. And with a simple project come a simple intro (mostly). But fret not, Fortran can be simple or complex, depending on the size of the project.
-
program hello
implicit none
@@ -18,31 +19,29 @@ program hello
end program hello
In the good ol' days (before FORTRAN 77), when printing to console, you would write write(*,*)
,
- but with the release of FORTRAN 77, that became redundant, as you could use the newest keyword: print
.
In the good ol' days (before FORTRAN 77), when printing to console, you would write write(*,*)
,
+ but with the release of FORTRAN 77, that became redundant, as you could use the newest keyword: print
.
-
With modern compilers, running the newest Fortran standards, write(*,*) 'Hello world!'
and print *, 'Hello world!'
- will compile to the exact same assembly. So if you only need to print something to stdout, just use print *
- as it conveys the meaning of the code better. Plus we don't need the full functionality of write(*,*)
+ With modern compilers, running the newest Fortran standards, write(*,*) 'Hello world!'
+ and print *, 'Hello world!'
+ will compile to the exact same assembly. So if you only need to print something to stdout, just use print *
+ as it conveys the meaning of the code better. Plus we don't need the full functionality of write(*,*)
in this example.
$ gfortran -o hello main.f90
$ ./hello
Hello world!
Now, hear me out, why not spice up the program a little bit more? What if we want to read user input? Well, fret +
Now, hear me out, why not spice up the program a little bit more? What if we want to read user input? Well, fret not my friend, because I have just the solution for you then. All we gotta do is to read from the terminal, and then print out the value.
-
program hello
implicit none
@@ -60,33 +59,30 @@ program hello
end program hello
So what we're seeing here, is that we have created two variables: usertxt
and ios
.
- usertxt
is the input we're reading from the terminal. Although since Fortran 90 doesn't
- have an explicit string type, doesn't mean we can't read or write text, as the character
+
So what we're seeing here, is that we have created two variables: usertxt
+ and ios
.
+ usertxt
is the input we're reading from the terminal. Although since Fortran 90 doesn't
+ have an explicit string type, doesn't mean we can't read or write text, as the character
type is just an array of 1000 characters long. It doesn't have to be 1000 characters, but it's what I chose on a
- whim.
The other variable, ios
, I probably don't need to introduce, as it's just an integer.
+ The other variable, ios
, I probably don't need to introduce, as it's just an integer.
But what control-flow this value holds, I feel is quite important, as a lot of file-based business logic makes
- use of it.
Introducing, iostat
. AKA, Input/Output Status Specifier. It indicates the status of the
+ Introducing, iostat
. AKA, Input/Output Status Specifier. It indicates the status of the
I/O operation. If the integer is positive, it indicates an error code. If it's negative, it indicates an end of file
condition. If it's zero, then it does not indicate anything yet. No error, no End Of File, no particular condition
- has triggered yet.
So in this case, where we check if ios
is End Of File, then that means if we input an
+ So in this case, where we check if ios
is End Of File, then that means if we input an
End Of File key combination (Ctrl+D on Unix/Linux, and Ctrl+Z on Windows), then the program would stop immediately.
- We use the trim()
function to remove any trailing whitespaces. That's because, if you
+ We use the trim()
function to remove any trailing whitespaces. That's because, if you
make a character array longer than the actual text, it will be filled with whitespace after the text. So now the output
looks like this:
$ gfortran -o hello main.f90
$ ./hello
diff --git a/src/components/Fortran/Fortran_Index.vue b/src/components/Fortran/Fortran_Index.vue
index 83f7299..9d49d44 100644
--- a/src/components/Fortran/Fortran_Index.vue
+++ b/src/components/Fortran/Fortran_Index.vue
@@ -23,6 +23,7 @@
> Set Up
> Hello World
+ > Data Types
> Reading A File
If you're familiar with C, then you would feel right at home with Fortran's build environment. There isn't really
an "official" compiler for the language, only a standard, that has to be implemented by the compilers. But there
are a lot of great compilers, that might as well be "official."
+
The top listed compiler on Fortran's website, is the GNU Fortran compiler (gfortran). It's the one I will be using
throughout the examples on the site. Unless stated otherwise. There are also some other notable compilers, that
has some rather interesting qualities to them.
bin
folder. Your layout doesn't need to look like this specifically, nor does it have to contain
the same folders. Each project is different, and so are the requirements. But this layout is simple, and great
for medium to large projects.Notes:
+
+
+
\ No newline at end of file