Add Fortran Data Types Page

This commit is contained in:
Rasmus Rasmussen 2025-02-13 14:55:32 +01:00
parent 3bd11d29c4
commit f8a6148ac7
8 changed files with 470 additions and 87 deletions

View File

@ -1,58 +1,6 @@
<script setup lang="ts">
import {ref} from "vue";
const toolbar = ref<boolean>(false);
const canGoForward = ref<boolean>(false);
const canGoBack = ref<boolean>(false);
function activateToolbar() {
toolbar.value = !toolbar.value;
}
function goBack() {
canGoBack.value = window.history.length <= 1;
history.back();
}
function goForward() {
canGoForward.value = window.history.length <= 1;
history.forward();
}
</script>
<template>
<div class="flex flex-col min-h-screen bg-var_background">
<div v-if="toolbar">
<div class="w-full py-small bg-ancient_highlight shadow-xl"></div>
<div class="w-full py-small bg-ancient_shadow"></div>
<div class="flex justify-center bg-ancient">
<div class="w-full max-w-screen-lg px-4">
<button @click="goBack" v-if="canGoBack">
<img src="/public/Icons/toolbar/Back.avif" width="32px" height="32px" class="mx-2" alt="Ancient looking back button">
</button>
<button @click="goBack" v-if="!canGoBack" disabled>
<img src="/public/Icons/toolbar/Back_Gray.avif" width="32px" height="32px" class="mx-2" alt="Ancient looking back button">
</button>
<button @click="goForward" v-if="canGoForward">
<img src="/public/Icons/toolbar/Forward.avif" width="32px" height="32px" class="mx-2" alt="Ancient looking forward button">
</button>
<button @click="goForward" v-if="!canGoForward" disabled>
<img src="/public/Icons/toolbar/Forward_Gray.avif" width="32px" height="32px" class="mx-2" alt="Ancient looking forward button">
</button>
<button><img src="/public/Icons/toolbar/Refresh.avif" width="20px" height="32px" class="mx-2" alt="Ancient looking forward button"></button>
</div>
</div>
<div class="w-full py-small bg-ancient_highlight shadow-xl"></div>
<div class="w-full py-small bg-ancient_shadow"></div>
</div>
<header class="flex justify-center">
<nav class="pt-10 text-2xl flex place-items-center">
<RouterLink class="mx-1" to="/">Home</RouterLink>
@ -71,7 +19,6 @@ function goForward() {
<footer class="flex justify-center pt-10 mt-10 pb-2">
<h5>Author: Still under construction</h5>
<button @click="activateToolbar">Time travel</button>
</footer>
</div>

View File

@ -58,11 +58,11 @@
too far from my apartment.</p>
<br>
<img src="/public/Images/avif/PXL_20230708_030149199_scaled.avif" alt="Meadow with fog." loading="lazy" decoding="async" width="1434" height="1080">
<img src="/Images/avif/PXL_20230708_030149199_scaled.avif" alt="Meadow with fog." loading="lazy" decoding="async" width="1434" height="1080">
<p>Not bad huh? The things you see when everyone is asleep.</p>
<br>
<img src="/public/Images/avif/PXL_20230720_032828882_scaled.avif" alt="My humble bike." loading="lazy" decoding="async" width="1434" height="1080">
<img src="/Images/avif/PXL_20230720_032828882_scaled.avif" alt="My humble bike." loading="lazy" decoding="async" width="1434" height="1080">
<p>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+.</p>

View File

@ -0,0 +1,425 @@
<script setup lang="ts">
import CodeTag from "../../../tags/CodeTag.vue";
</script>
<template>
<div>
<h1 class="text-3xl">Data Types</h1>
<hr class="mb-6">
<p class="mb-6">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.<br><br>
Let's look at a small list of some common types.
</p>
<ul class="mb-6">
<li>&gt; <code>integer</code></li>
<li>&gt; <code>real</code></li>
<li>&gt; <code>double precision</code></li>
<li>&gt; <code>logical</code></li>
<li>&gt; <code>character</code></li>
</ul>
<p class="mb-6"><code class="text-red-500">integer</code> is, if you hadn't guessed, a whole number. Like most languages,
<code class="text-red-500">int</code>. The <code class="text-red-500">real</code> type is like a
<code class="text-red-500">float</code>. 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.<br><br>
The <code class="text-red-500">double precision</code> is a double, obviously. And as you have probably guessed at
this point, <code class="text-red-500">logical</code> is a boolean. <code class="text-red-500">character</code>
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: <code class="text-red-500">VARCHAR(256)</code>.</p>
<h2 class="text-2xl">integer</h2>
<hr class="mb-6">
<p class="mb-6">In Fortran, you can specify the size of an integer at declaration. You do that with <code class="text-red-500">(kind = n)</code>.
So if you want a 16 bit integer, you do <code class="text-red-500">integer(kind = 16)</code>. Observe the following code example.
As an exercise for the reader, try to imagine what would be printed to the terminal.<br><br>
*Do note that we're using Fortran 90, and not the newer versions that supports unsigned integers.<a href="#footnote-1">[1]</a>
</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
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
</code></pre>
</div>
<p class="mb-6">Now, as the astute reader might have already figured, the output would look like this:</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./a.out
int
2147483647
kind = 2
32767
kind = 4
2147483647
kind = 8
9223372036854775807
kind = 16
170141183460469231731687303715884105727
</code></pre>
</div>
<p class="mb-6">The <code-tag>huge(n)</code-tag> function simply assigns the highest largest number of any integer,
real or array type of any kind.<br><br>
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.<br><br>
Usually, unless your working with huge datasets, <code-tag>integer</code-tag> or if you want to be more semantic,
<code-tag>integer(kind = 4)</code-tag> would be more than sufficient to work with.
</p>
<h2 class="text-2xl">real</h2>
<hr class="mb-6">
<p class="mb-6">The <code-tag>real</code-tag> type is, in most other languages, a <code-tag>float</code-tag>. And with
integers, real can also be specified with a <code-tag>kind(n)</code-tag> modifier. Observe this example:</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
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
</code></pre>
</div>
<p class="mb-6">The output:</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./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
</code></pre>
</div>
<p class="mb-6">As you can see here, we have included a new print statement. <code-tag>tiny(n)</code-tag> returns
the smallest positive number of a real kind. That function is not available for integers.</p>
<h2 class="text-2xl">double precision</h2>
<hr class="mb-6">
<p class="mb-6"><code-tag>double precision</code-tag> is pretty much just a bigger version of real. All of the same rules apply
to double precision as the real type.</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
program hello
implicit none
double precision :: double;
print *, 'real'
print *, huge(double)
print *, tiny(double)
end program hello
</code></pre>
</div>
<p class="mb-6">And the output looks like this:</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./a.out
real
1.7976931348623157E+308
2.2250738585072014E-308
</code></pre>
</div>
<p class="mb-6"><code-tag>double precision</code-tag> does not support the kind modifier. A double precision number is
also the same as an 8 byte real.</p>
<h2 class="text-2xl">logical</h2>
<hr class="mb-6">
<p class="mb-6"><code-tag>logical</code-tag> is a boolean. It's either true or false. But a funny thing with the logical type in
Fortran, compared to other languages, is that you can define the size of it. The logical type supports the
<code-tag>kind(n)</code-tag> modifier.</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
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
</code></pre>
</div>
<p class="mb-6">Now I have a small exercise for the reader again. Let's assume that we are using <code-tag>gfortran</code-tag>
without specifying an optimization level. What do you think the output would look like?</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./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
</code></pre>
</div>
<p class="mb-6">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. <a href="#footnote-1">[2]</a><br><br>
A good programming practise is to always assign your logical when creating them.</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
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.;
</code></pre>
</div>
<p class="mb-6">Now, the output looks as expected.</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./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
</code></pre>
</div>
<h2 class="text-2xl">character</h2>
<hr class="mb-6">
<p class="mb-6"><code-tag>character</code-tag> in fortran can be seen as either a <code-tag>char</code-tag> or
a <code-tag>string</code-tag> in other languages, depending on the length you give it.<br><br>
Observe the example below.</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
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
</code></pre>
</div>
<p class="mb-6">Output looks like this:</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./a.out
character
value: 4
size: 1
value: a
size: 10
value: a lol
size: 10
</code></pre>
</div>
<p class="mb-6">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.<br><br>
To mitigate this, we could either set the correct length when creating the character, or we could use the <code-tag>trim(value)</code-tag>
function. It removes trailing whitespaces from strings.</p>
<code-tag>main.f90</code-tag>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
trim(char2)//'lol';
</code></pre>
</div>
<p class="mb-6">Now, the output should be fixed:</p>
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
&gt; gfortran main.f90
&gt; ./a.out
character
value:
size: 1
value: a
size: 10
value: a lol
size: 10
with trim
value: alol
size: 10
</code></pre>
</div>
<p>Footnotes:</p>
<ul>
<li id="footnote-1">[1] <a href="https://gcc.gnu.org/onlinedocs/gfortran/Unsigned-integers.html" class="underline">unsigned integers with gfortran</a></li>
<li id="footnote-2">[2] <a href="https://stackoverflow.com/a/71190625" class="underline">Why would using uninitialized variables in Fortran ever work? [duplicate]</a></li>
</ul>
</div>
</template>
<style scoped>
</style>

View File

@ -5,12 +5,13 @@
<template>
<div>
<h1 class="text-3xl">Hello World In Fortran 90</h1>
<hr>
<p>A Hello World program is always a great step into a new programming language. It gives a simple oversight into
<hr class="mb-6">
<p class="mb-6">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.</p>
<div class="font-mono shadow-xl p-2">
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
program hello
implicit none
@ -18,31 +19,29 @@ program hello
end program hello
</code></pre>
</div>
<br>
<p>In the good ol' days (before FORTRAN 77), when printing to console, you would write <span><code>write(*,*)</code></span>,
but with the release of FORTRAN 77, that became redundant, as you could use the newest keyword: <span><code>print</code></span>.</p>
<br>
<p class="mb-6">In the good ol' days (before FORTRAN 77), when printing to console, you would write <span><code class="text-red-500">write(*,*)</code></span>,
but with the release of FORTRAN 77, that became redundant, as you could use the newest keyword: <span><code class="text-red-500">print</code></span>. <br><br>
<p>With modern compilers, running the newest Fortran standards, <span><code>write(*,*) 'Hello world!'</code> and <code>print *, 'Hello world!'</code></span>
will compile to the exact same assembly. So if you only need to print something to stdout, just use <span><code>print *</code></span>
as it conveys the meaning of the code better. Plus we don't need the full functionality of <span><code>write(*,*)</code></span>
With modern compilers, running the newest Fortran standards, <span><code class="text-red-500">write(*,*) 'Hello world!'</code>
and <code class="text-red-500">print *, 'Hello world!'</code></span>
will compile to the exact same assembly. So if you only need to print something to stdout, just use <span><code class="text-red-500">print *</code></span>
as it conveys the meaning of the code better. Plus we don't need the full functionality of <span><code class="text-red-500">write(*,*)</code></span>
in this example.</p>
<div class="font-mono shadow-xl p-2">
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
$ gfortran -o hello main.f90
$ ./hello
Hello world!
</code></pre>
</div>
<br>
<p>Now, hear me out, why not spice up the program a little bit more? What if we want to read user input? Well, fret
<p class="mb-6">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.</p>
<div class="font-mono shadow-xl p-2">
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
program hello
implicit none
@ -60,33 +59,30 @@ program hello
end program hello
</code></pre>
</div>
<br>
<p>So what we're seeing here, is that we have created two variables: <span><code>usertxt</code> and <code>ios</code></span>.
<span><code>usertxt</code></span> 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 <span><code>character</code></span>
<p class="mb-6">So what we're seeing here, is that we have created two variables: <span><code class="text-red-500">usertxt</code>
and <code class="text-red-500">ios</code></span>.
<span><code class="text-red-500">usertxt</code></span> 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 <span><code class="text-red-500">character</code></span>
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.</p>
<br>
whim.<br><br>
<p>The other variable, <span><code>ios</code></span>, I probably don't need to introduce, as it's just an integer.
The other variable, <span><code class="text-red-500">ios</code></span>, 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.</p>
<br>
use of it.<br><br>
<p>Introducing, <span><code>iostat</code></span>. AKA, Input/Output Status Specifier. It indicates the status of the
Introducing, <span><code class="text-red-500">iostat</code></span>. 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.</p>
<br>
has triggered yet.<br><br>
<p>So in this case, where we check if <span><code>ios</code></span> is End Of File, then that means if we input an
So in this case, where we check if <span><code class="text-red-500">ios</code></span> 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 <span><code>trim()</code></span> function to remove any trailing whitespaces. That's because, if you
We use the <span><code class="text-red-500">trim()</code></span> 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:</p>
<div class="font-mono shadow-xl p-2">
<div class="font-mono shadow-lg shadow-slate-500 p-2 mb-6">
<pre><code class="text-sm">
$ gfortran -o hello main.f90
$ ./hello

View File

@ -23,6 +23,7 @@
<ul>
<li><RouterLink to="/Fortran/SetUp">&gt; Set Up</RouterLink></li>
<li><RouterLink to="/Fortran/HelloWorld">&gt; Hello World</RouterLink></li>
<li><RouterLink to="/Fortran/DataTypes">&gt; Data Types</RouterLink></li>
<li><RouterLink to="/Fortran/ReadingAFile">&gt; Reading A File</RouterLink></li>
</ul>
</div>

View File

@ -10,6 +10,7 @@
<p class="mb-6">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."<br><br>
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.</p>
@ -45,6 +46,7 @@
and <code class="text-red-500">bin</code> 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.<br><br>
But if we're doing micro-projects, as in like, a hello world application, a test application, or a small tool,
this layout is rather redundant, and in the examples on this site, we will only use it on bigger projects,
and we will let you know, when or how we set up the project.</p>
@ -62,7 +64,6 @@ project/
Makefile # Build script
</code></pre>
</div>
<br>
<p>Notes:</p>
<ul class="mb-6">

View File

@ -11,6 +11,7 @@ import LispIndex from "./components/Lisp/Lisp_Index.vue";
import FortranReadingFiles from "./components/Fortran/Fortran_Reading_Files.vue";
import FortranHelloWorld from "./components/Fortran/Fortran_Hello_World.vue";
import FortranSetUp from "./components/Fortran/Fortran_Set_Up.vue";
import FortranDataTypes from "./components/Fortran/Fortran_Data_Types.vue";
const router = createRouter({
history: createWebHistory(),
@ -21,6 +22,7 @@ const router = createRouter({
{path: '/Fortran', name: 'Fortran', component: FortranIndex},
{path: '/Fortran/SetUp', name: 'SetUp', component: FortranSetUp},
{path: '/Fortran/HelloWorld', name: 'HelloWorld', component: FortranHelloWorld},
{path: '/Fortran/DataTypes', name: 'DataTypes', component: FortranDataTypes},
{path: '/Fortran/ReadingAFile', name: 'ReadingAFile', component: FortranReadingFiles},
{path: '/Pascal', name: 'Pascal', component: PascalIndex},
@ -30,4 +32,4 @@ const router = createRouter({
]
})
createApp(App).use(router).mount('#app')
createApp(App).use(router).mount('#app')

11
tags/CodeTag.vue Normal file
View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<code class="text-red-500"><slot></slot></code>
</template>
<style scoped>
</style>