FORTRAN: Difference between revisions

From BlueM
Jump to navigation Jump to search
m (fix source formatting)
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Fixed Form und Free Form ==
<div style="float:right; margin-left:10px;">__TOC__</div>
Die Free Form ist der Fixed Form der übersichtlichkeitshalber vorzuziehen. Ausserdem können bei der Fixed Form Fehler entstehen, die der compiler nicht abfängt (z. B. Formeln die über den Rand gehen - in SMUSI war beispielsweise eine Stelle, wo statt mit 300 nur mit 3 multipliziert wurde.
== Real Werte und Vergleiche ==
Ein wichtiger Punkt bei der Programmierung mit Fortran ist die Behandlung der Real Werte. Insbesondere der vergleich, ob zwei Real Werte gleich sind, ist in FORTRAN nur durch eine erweiterte Syntax möglich.
 
=== Zuweisen von Werten ===
<source lang="fortran">
real*4 a
real*8 b


Für die Umstellung gibts hier eine regular Expression, die alle Zeilen anzeigt die länger als 72 Zeichen sind:
a = 0.123e0 !das e0 kennzeichnet den Wert als real*4
b = 0.123d0 !das d0 kennzeichnet den Wert als real*8</source>


Identizieren von Problemstellen
=== Vergleich von Realzahlen ===
<pre>
:''siehe Bug 367''
^[^cC!][^!]^72
Früher wurde im Rechenkern mit unterschiedlichen Vergleichen gerechnet (<code>GLOBAL_NULL</code>, <code>GLOBAL_FASTNULL</code> etc.)
</pre>


Bereinigen von Leerzeichen am Ende
'''Momentan verwendet:'''
<pre>
<source lang="fortran">
(:b+)$
R8_EPSILON = 2 * Epsilon(1.2345d0)
</pre>
R4_EPSILON = 2 * Epsilon(1.2654E0) ! entspricht 2**-23</source>


== Real Werte und Vergleiche ==
'''Diskussion:'''
Ein wichtiger Punkt bei der Programmierung mit Fortran ist die Behandlung der Real Werte. Insbesondere der vergleich, ob zwei Real Werte gelich sind, ist in FORTRAN nur durch eine erweiterte Syntax möglich.
<source lang="fortran">
real*4 a
real*4 b
logical isNull


=== Zuweisen von Werten: ===
isNull = (a == b)                      !wird so gut wie nie erfüllt


<fortran>
isNull = (ABS(a - b) < 1E-15)          !früher im Projekt verwendet (GLOBAL_NULL)
real*4 a
real*8 b


a = 0.123e0 !das e0 kennzeichnet den Wert als real*4
!Alternativen (zur Diskussion)
isNull = (ABS(a - b) < Epsilon(a))      !nach Rechenoperationen erwies sich Epsilon als zu ungenau bzw. genau
isNull = (ABS(a / b - 1.0E0) < eps)    !Relativvergleich - führte bei Tests aber zu Fehlern
isNull = (ABS(a - b) < SPACING(0.0E0))</source>


b = 0.123d0 ! das d0 kennzeichnet den Wert als real*8
====Anmerkung====
</fortran>
Im Code von BlueM sind ein paar nicht korrekte Anweisungen enthalten:
<source lang="fortran">
! FALSCH
MAX(dumdidum, R8_EPSILON)
MAX(dumdidum, R4_EPSILON)</source>
Korrekt ist aber:
<source lang=fortran>
! RICHTIG
MAX(dumdidum, 0.0D0)
MAX(dumdidum, 0.0E0)</source>


==== Links ====
* [http://hodgson.pi.tu-berlin.de/Lehre/EDV1/skripte/f95_skript/node56.html Vergleich von Realwerten]
* [http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231255.aspx Aus dem Intel-Forum]
* Guter Artikel über Problematik: [http://www.lahey.com/float.htm The Perils of Floating Point]


=== Vergleich von Realzahlen ===
== Übergabe von Arrays ==
Momentan wird im Rechenkern mit unterschiedlichen Vergelichen gerechnet (global_fastnull etc.)
In Fortran ist es möglich Teile von Arrays an Funktionen zu übergeben.  


Momentaner Favorit ist: FortranEpsilonfürNull =  2 * Epsilon(...)
Dabei wird der Subroutine (oder function) einfach der "Anfangswert" übergeben - z.B. <code>func_array(Huba(1,2,1))</code>.Von diesem Startpunkt wird, dann in der Subroutine ein entsprechendes Array gebildet. Erwartet beispielsweise die Subroutine einen Vektor, dann werden vom jenem Startpunkt an alle Werte der ersten Dimension übernommen. Analog verhält es sich bei mehrdimiensionalen Arrays.  
;Anmerkung: Das Array der Subroutine sollte natürlich kleiner sein, als das Übergebene (vom Startpunkt gezählt) !


;Anmerkung: Im Code von BlueM sind ein paar nicht korrekte Anweisungen enthalten: MAX(dumdidum,global_FastNull). Korrekt ist MAX(dumdidum,0.0E0)
Das Beispiel verdeutlicht dies:
<source lang="fortran">
!---------------------------------------------------------------
    subroutine TestArrayFortranFortran()
    integer arr(3,4)
    integer i
    integer j


<fortran>
    do i = 1, ubound(arr,1)
real*4 a
        do j = 1, ubound(arr,2)
real*4 b
            arr(i,j) = i + (j-1)*3
logical isNull
            write(*,'("Matrix (", I4,",",I4,") = ",I4)') i,j,arr(i,j)
        end do
    end do
   
    write(*,'("Aufruf mit arr(1,1) ")')
    call TestArrayFortranFortran_SUB(arr(1,1))
    write(*,'("Aufruf mit arr(2,1) ")')
    call TestArrayFortranFortran_SUB(arr(2,1))
    write(*,'("Aufruf mit arr(1,2) ")')
    call TestArrayFortranFortran_SUB(arr(1,2))
    write(*,'("Aufruf mit arr(2,2) ")')
    call TestArrayFortranFortran_SUB(arr(2,2))


    end subroutine
!---------------------------------------------------------------


isNull =(a == b) !wird sogut wie nie erfüllt


isNull = (a - b < global_fastnull) !aktuell im Projekt verwendet
!---------------------------------------------------------------
    subroutine TestArrayFortranFortran_SUB(arr)
    integer arr(2)
    integer i
   
    do i = 1, ubound(arr,1)
        write(*,'("Vektor ", I4)') arr(i)
    end do


    end subroutine
!---------------------------------------------------------------
</source>


!Alternativen (zur Diskussion)
Ausgabe:
[[Bild:ConsolenAusgabe TestArray.png]]


!isnull = (abs(a - b) < Epsilon(a)) ! nach Rechenoperationen erwies sich Epsilon als zu ungenau bzw. genau
== Fixed Form und Free Form ==
!isnull = (abs(a/b-1.0E0) < eps) !Relativvergleich - führte bei Tests aber zu Fehlern
Die Free Form ist der Fixed Form der übersichtlichkeitshalber vorzuziehen. Ausserdem können bei der Fixed Form Fehler entstehen, die der compiler nicht abfängt (z. B. Formeln die über den Rand gehen - in SMUSI war beispielsweise eine Stelle, wo statt mit 300 nur mit 3 multipliziert wurde.


isNull = (abs(a-b) < SPACING(0.0E0))
Für die Umstellung gibts hier eine regular Expression, die alle Zeilen anzeigt die länger als 72 Zeichen sind:
</fortran>


==== Links: ====
Identifizieren von Problemstellen
Vergleich von Realwerten [http://hodgson.pi.tu-berlin.de/Lehre/EDV1/skripte/f95_skript/node56.html]
<pre>
[http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231255.aspx|Aus dem intelforum]
^[^cC!][^!]^72
Guter Artikel über Problemetik: [http://www.lahey.com/float.htm|The Perils of Floating Point]
</pre>
Visualisierung unter [http://strfriend.com/vis?re=^%5b^cC!%5d%5b^!%5d^72%0D%0A]


Bereinigen von Leerzeichen am Ende
<pre>
(:b+)$
</pre>
Visualisierung unter [http://strfriend.com/vis?re=(%3Ab%2B)%24%0D%0A]


[[Kategorie: Fortran]]]
[[Kategorie: Fortran]]

Latest revision as of 05:57, 27 January 2018

Real Werte und Vergleiche

Ein wichtiger Punkt bei der Programmierung mit Fortran ist die Behandlung der Real Werte. Insbesondere der vergleich, ob zwei Real Werte gleich sind, ist in FORTRAN nur durch eine erweiterte Syntax möglich.

Zuweisen von Werten

real*4 a
real*8 b

a = 0.123e0 !das e0 kennzeichnet den Wert als real*4
b = 0.123d0 !das d0 kennzeichnet den Wert als real*8

Vergleich von Realzahlen

siehe Bug 367

Früher wurde im Rechenkern mit unterschiedlichen Vergleichen gerechnet (GLOBAL_NULL, GLOBAL_FASTNULL etc.)

Momentan verwendet:

R8_EPSILON = 2 * Epsilon(1.2345d0)
R4_EPSILON = 2 * Epsilon(1.2654E0) ! entspricht 2**-23

Diskussion:

real*4 a
real*4 b
logical isNull

isNull = (a == b)                       !wird so gut wie nie erfüllt

isNull = (ABS(a - b) < 1E-15)           !früher im Projekt verwendet (GLOBAL_NULL)

!Alternativen (zur Diskussion)
isNull = (ABS(a - b) < Epsilon(a))      !nach Rechenoperationen erwies sich Epsilon als zu ungenau bzw. genau
isNull = (ABS(a / b - 1.0E0) < eps)     !Relativvergleich - führte bei Tests aber zu Fehlern
isNull = (ABS(a - b) < SPACING(0.0E0))

Anmerkung

Im Code von BlueM sind ein paar nicht korrekte Anweisungen enthalten:

! FALSCH
MAX(dumdidum, R8_EPSILON)
MAX(dumdidum, R4_EPSILON)

Korrekt ist aber:

! RICHTIG
MAX(dumdidum, 0.0D0)
MAX(dumdidum, 0.0E0)

Links

Übergabe von Arrays

In Fortran ist es möglich Teile von Arrays an Funktionen zu übergeben.

Dabei wird der Subroutine (oder function) einfach der "Anfangswert" übergeben - z.B. func_array(Huba(1,2,1)).Von diesem Startpunkt wird, dann in der Subroutine ein entsprechendes Array gebildet. Erwartet beispielsweise die Subroutine einen Vektor, dann werden vom jenem Startpunkt an alle Werte der ersten Dimension übernommen. Analog verhält es sich bei mehrdimiensionalen Arrays.

Anmerkung
Das Array der Subroutine sollte natürlich kleiner sein, als das Übergebene (vom Startpunkt gezählt) !

Das Beispiel verdeutlicht dies:

!---------------------------------------------------------------
    subroutine TestArrayFortranFortran()
    integer arr(3,4)
    integer i
    integer j

    do i = 1, ubound(arr,1)
        do j = 1, ubound(arr,2)
            arr(i,j) = i + (j-1)*3
            write(*,'("Matrix (", I4,",",I4,") = ",I4)') i,j,arr(i,j)
        end do
    end do
    
    write(*,'("Aufruf mit arr(1,1) ")')
    call TestArrayFortranFortran_SUB(arr(1,1))
    write(*,'("Aufruf mit arr(2,1) ")')
    call TestArrayFortranFortran_SUB(arr(2,1))
    write(*,'("Aufruf mit arr(1,2) ")')
    call TestArrayFortranFortran_SUB(arr(1,2))
    write(*,'("Aufruf mit arr(2,2) ")')
    call TestArrayFortranFortran_SUB(arr(2,2))

    end subroutine
!---------------------------------------------------------------


!---------------------------------------------------------------
    subroutine TestArrayFortranFortran_SUB(arr)
    integer arr(2)
    integer i
    
    do i = 1, ubound(arr,1)
        write(*,'("Vektor ", I4)') arr(i)
    end do

    end subroutine
!---------------------------------------------------------------

Ausgabe: ConsolenAusgabe TestArray.png

Fixed Form und Free Form

Die Free Form ist der Fixed Form der übersichtlichkeitshalber vorzuziehen. Ausserdem können bei der Fixed Form Fehler entstehen, die der compiler nicht abfängt (z. B. Formeln die über den Rand gehen - in SMUSI war beispielsweise eine Stelle, wo statt mit 300 nur mit 3 multipliziert wurde.

Für die Umstellung gibts hier eine regular Expression, die alle Zeilen anzeigt die länger als 72 Zeichen sind:

Identifizieren von Problemstellen

^[^cC!][^!]^72

Visualisierung unter [1]

Bereinigen von Leerzeichen am Ende

(:b+)$

Visualisierung unter [2]